Leetcode hot 100之回溯O(N!):选择/DFS

目录

框架:排列/组合/子集

元素无重不可复选

全排列

子集

组合:[1, n] 中的 k 个数

分割成回文串

元素无重不可复选:排序,多条值相同的只遍历第一条

子集/组合

先进行排序,让相同的元素靠在一起,如果发现 nums[i] == nums[i-1],则跳过 

排列

元素无重可复选

子集/组合:sum=target

排列:去除 used 剪枝

N皇后


如果不能成功,那么返回的时候我们就还要把这个位置还原。这就是回溯算法,也是试探算法。

解决一个回溯问题,实际上就是一个决策树的遍历过程

1、路径:已选择。

2、选择列表:可选择。

3、结束条件:无选择。

框架:排列/组合/子集

result = []
function backtrack(路径, 选择列表):if 满足结束条件:result.add(路径)result.push([...path])或者result.push(path.slice())//path还会改变,所以不能传引用地址returnfor 选择 in 选择列表:做选择pushbacktrack(路径, 选择列表)撤销选择pop数组(有一定的剪枝,不用判断是否use)
const backtrack = (start) => {// 回溯算法标准框架for (let i = start; i < nums.length; i++) {// 做选择track.push(nums[i]);// 回溯遍历下一层节点backtrack(i + 1);// 撤销选择track.pop();}};backtrack(0);
图
function backtrack(nums, used, track, res) {for (let i = 0; i < nums.length; i++) {if (used[i]) {continue;}track.push(nums[i]);used[i] = true;backtrack(nums, used, track, res);track.pop();used[i] = false;}
}全排列中
做选择/撤销选择 可用if(path.includes(item)) continue;代替

元素无重不可复选

全排列

key:

  1. path.length == string.length
  2. path.includes(item)
const _permute = string => {const res = [];const backtrace = path => {if(path.length == string.length){res.push(path);return;}for(const item of string) {if(path.includes(item)) continue;backtrace(path + item);}};backtrace('');return res;
}

子集

输入一个无重复元素的数组 nums,其中每个元素最多使用一次,请你返回 nums 的所有子集

比如输入 nums = [1,2,3],算法应该返回如下子集:

[ [],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3] ]

/*** @param {number[]} nums* @return {number[][]}*/
var subsets = function(nums) {// 用于存储结果const res = [];// 用于记录回溯路径const track = [];/*** 回溯算法的核心函数,用于遍历子集问题的回溯树* @param {number} start - 控制树枝的遍历,避免产生重复子集*/const backtrack = (start) => {// 前序遍历位置,每个节点的值都是一个子集res.push([...track]);// 回溯算法标准框架for (let i = start; i < nums.length; i++) {// 做选择track.push(nums[i]);// 回溯遍历下一层节点backtrack(i + 1);// 撤销选择track.pop();}};backtrack(0);return res;
};

组合:[1, n] 中的 k 个数

返回范围 [1, n] 中所有可能的 k 个数的组合,剪枝

let result = []
let path = []
var combine = function(n, k) {result = []combineHelper(n, k, 1)return result
};
const combineHelper = (n, k, startIndex) => {if (path.length === k) {result.push([...path])return}for (let i = startIndex; i <= n - (k - path.length) + 1; ++i) {path.push(i)combineHelper(n, k, i + 1)path.pop()}
}

分割成回文串

  • 组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个.....。
  • 切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段.....。

/*** @param {string} s* @return {string[][]}*/
const isPalindrome = (s, l, r) => {for (let i = l, j = r; i < j; i++, j--) {if(s[i] !== s[j]) return false;}return true;
}var partition = function(s) {const res = [], path = [], len = s.length;backtracking(0);return res;function backtracking(startIndex) {if(startIndex >= len) {res.push(Array.from(path));return;}for(let i = startIndex; i < len; i++) {if(!isPalindrome(s, startIndex, i)) continue;path.push(s.slice(startIndex, i + 1));backtracking(i + 1);path.pop();}}
};

元素无重不可复选:排序,多条值相同的只遍历第一条

子集/组合

nums = [1,2,2],你应该输出:

[ [],[1],[2],[1,2],[2,2],[1,2,2] ]

如果一个节点有多条值相同的树枝相邻,则只遍历第一条,剩下的都剪掉,不要去遍历:

先进行排序,让相同的元素靠在一起,如果发现 nums[i] == nums[i-1],则跳过 

排列

// 注意:javascript 代码由 chatGPT🤖 根据我的 java 代码翻译,旨在帮助不同背景的读者理解算法逻辑。
// 本代码还未经过力扣测试,仅供参考,如有疑惑,可以参照我写的 java 代码对比查看。/*** @param {number[]} nums* @return {number[][]}*/var permuteUnique = function(nums) {let res = [];let track = [];let used = new Array(nums.length).fill(false);// 先排序,让相同的元素靠在一起nums.sort((a, b) => a - b);backtrack(nums, used, track, res);return res;
};/*** @param {number[]} nums* @param {boolean[]} used* @param {number[]} track* @param {number[][]} res*/
function backtrack(nums, used, track, res) {if (track.length === nums.length) {res.push(track.slice());return;}for (let i = 0; i < nums.length; i++) {if (used[i]) {continue;}// 新添加的剪枝逻辑,固定相同的元素在排列中的相对位置if (i > 0 && nums[i] === nums[i - 1] && !used[i - 1]) {continue;}track.push(nums[i]);used[i] = true;backtrack(nums, used, track, res);track.pop();used[i] = false;}
}

元素无重可复选

子集/组合:sum=target

想让每个元素被重复使用,我只要把 i + 1 改成 i 即可

给之前的回溯树添加了一条树枝,在遍历这棵树的过程中,一个元素可以被无限次使用

这棵回溯树会永远生长下去,所以我们的递归函数需要设置合适的 base case 以结束算法,即路径和大于 target 时就没必要再遍历下去了 

排列:去除 used 剪枝

N皇后

在 n * n 的棋盘上要摆 n 个皇后,
要求:任何两个皇后不同行,不同列不在同一条斜线上,
求给一个整数 n ,返回 n 皇后的摆法数。

要求:空间复杂度 O(1) ,时间复杂度O(n!)

  1. 要确定皇后的位置,其实就是确定列的位置,因为行已经固定了
  2. 进一步讲,也就是如何摆放 数组arr [0,1,2,3,...,n-1]
  3. 如果没有【不在同一条斜线上】要求,这题其实只是单纯的全排列问题
  4. 在全排列的基础上,根据N皇后的问题,去除一些结果
  • arr :n个皇后的列位置

  • res :n皇后排列结果

  • ruler: 记录对应的列位置是否已经占用(也是是否有皇后),如果有,那么设为1,没有设为0

  • setPos :哈希集合,标记正斜线(从左上到右下)位置,如果在相同正斜线上,坐标(x,y)满足 y-x 都相同,(y1 - x1)应该等于(y2 - x2)

  • setCon :哈希集合,标记反正斜线(从y右上到左下)位置,如果在相同反斜线上,坐标(x,y)满足 x+y 都相同,(x1 + y1)应该等于(x2 + y2)

  • 是否在同一斜线上,其实就是这两个点的所形成的斜线的斜率是否为±1。点P(a,b) ,点Q(c,d)

    (1)斜率为1 (d-b)/(c-a) = 1,横纵坐标之差相等

    (2)斜率为-1 (d-b)/(c-a) = -1 ,等式两边恒等变形 a+b = c + d ,横纵坐标之和相等

/**** @param n int整型 the n* @return int整型*/
function Nqueen(n) {let res = []; //二维数组,存放每行Q的列坐标let isQ = new Array(n).fill(0); //记录该列是否有Qlet setPos = new Set(); //标记正对角线let setCon = new Set(); // 标记反对角线//给当前row找一个colconst backTrace = (row, path) => {if (path.length === n) {res.push(path);return;}for (let col = 0; col < n; col++) {if (isQ[col] == 0 &&!setPos.has(row - col) &&!setCon.has(row + col)) {path.push(col);isQ[col] = 1;setPos.add(row - col);setCon.add(row + col);backTrace(row + 1, path);path.pop();isQ[col] = 0;setPos.delete(row - col);setCon.delete(row + col);}}};backTrace(0, []);return res.length;
}
module.exports = {Nqueen: Nqueen,
};

动态规划的暴力求解阶段就是回溯算法。只是有的问题具有重叠子问题性质,可以用 dp table 或者备忘录优化,将递归树大幅剪枝,这就变成了动态规划。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/97321.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端代码格式化规范总结

在日常开发过程中&#xff0c;经常会碰到代码格式化不一致的问题&#xff0c;还要就是 js 代码语法错误等没有及时发行改正&#xff0c;下面就介绍一下如何使用eslint、prettier、husky、lint-staged、commitizen来规范代码格式和提高代码质量的方法。 目录 准备工作代码检测代…

VMProtect使用教程(VC++MFC中使用)

VMProtect使用教程(VCMFC中使用) VMProtect是一种商业级别的代码保护工具&#xff0c;可以用于保护VC MFC程序。以下是使用VMProtect保护VC MFC程序的步骤&#xff1a; 1. 下载并安装VMProtect,C包含库及目录。 2. 在VC MFC项目中添加VMProtectSDK.h头文件&#xff0c;并在需…

Photoshop 笔记

目录 1. Photoshop 笔记1.1. 创建 A4 大小图片 1. Photoshop 笔记 1.1. 创建 A4 大小图片 Photoshop 的高版本自带了 A4、A5、A3、B5、B4、B3、C4、C5 等, 也可以直接制作打印美国信纸尺寸、法律文件用低、小报用纸等。 方法是: 新建 > 打印, 然后选择就可以了。 如果使…

Android ncnn-android-yolov8-seg源码解析 : 实现人像分割

1. 前言 上篇文章&#xff0c;我们已经将人像分割的ncnn-android-yolov8-seg项目运行起来了&#xff0c;后续文章我们会抽取出Demo中的核心代码&#xff0c;在自己的项目中&#xff0c;来接入人体识别和人像分割功能。 先来看下效果&#xff0c;整个图像的是相机的原图&#…

番外--Task2:

任务&#xff1a;root与普通用户的互切&#xff08;区别&#xff09;&#xff0c;启动的多用户文本见面与图形界面的互切命令&#xff08;区别&#xff09;。 输入图示命令&#xff0c;重启后就由图形界面转成文本登录界面&#xff1b; 输入图示命令&#xff0c;重启后就由文本…

java实验(头歌)--类的继承以及抽象类的定义和使用

文章目录 第一题第二题第三题 第一题 import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.Scanner;//把main 函数的给替换了 public static vo…

MybatisPlus01

MybatisPlus01 1.MybatisPlus初体验 1.1首先要引入MybatisPlus的依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency>1.2定义Mapp…

es官方为我们提供的堆内存保护机制-熔断器( breaker )

总熔断器&#xff08;相当于似乎总闸&#xff09; 参数&#xff1a; indices.breaker.total.use_real_memory 默认值&#xff1a;true 在 elasticsearch.yml中配置。 参数&#xff1a; indices.breaker.total.limit 如果 indices.breaker.total.use_real_memory : true, in…

Java网络编程入门指南:实现一个多人聊天室

java网络&#xff1a;实现一个多人聊天室 Socket编程Socket基础TCP和UDP 服务器-客户端通信创建服务器创建客户端 HTTP通信HTTP请求HTTP响应 RMI远程方法调用创建RMI服务创建RMI客户端 多人聊天室 简介 Java网络编程是一种通过网络连接和通信来实现应用程序之间数据传输的技术。…

【JavaEE初阶】 Thread类及常见方法

文章目录 &#x1f334;Thread类的概念&#x1f333;Thread 的常见构造方法&#x1f384;Thread 的几个常见属性&#x1f340;start()-启动一个线程&#x1f332;中断一个线程&#x1f6a9;实例一&#x1f6a9;实例二&#x1f6a9;实例三 &#x1f38d;join()-等待一个线程&…

想要开发一款游戏, 需要注意什么?

开发一款游戏是一个复杂而令人兴奋的过程。游戏开发是指创建、设计、制作和发布电子游戏的过程。它涵盖了从最初的概念和创意阶段到最终的游戏发布和维护阶段的各个方面。 以下是一些需要注意的关键事项&#xff1a; 游戏概念和目标&#xff1a; 确定游戏开发的核心概念和目标…

【SpringBoot】| Thymeleaf 模板引擎

目录 Thymeleaf 模板引擎 1. 第一个例子 2. 表达式 ①标准变量表达式 ②选择变量表达式&#xff08;星号变量表达式&#xff09; ③链接表达式&#xff08;URL表达式&#xff09; 3. Thymeleaf的属性 ①th:action ②th:method ③th:href ④th:src ⑤th:text ⑥th:…

TCP相关面试题

TCP相关面试题 题目1 介绍一下TCP三次握手的过程 介绍TCP三次握手应该从3个方面进行回答&#xff0c;分别是数据包名称&#xff0c;客户端与服务端的状态变化&#xff0c;数据包的序号变化。而不能只是简单回答发送的数据包名称。 TCP三次握手的过程如下&#xff1a; 从数据…

vue3通过ref获取子组件defineExpose的数据和方法

1. 父组件: <script setup> import { defineAsyncComponent, watchEffect, toRefs, reactive } from vue;// 异步组件 const Test defineAsyncComponent(()>import(./xx/Test.vue))const child1Ref ref(null) const state reactive({age: 1,name: 2,sayHello: nul…

NSSCTF [BJDCTF 2020]easy_md5 md5实现sql

开局一个框 啥都没有用 然后我们进行抓包 发现存在提示 这里是一个sql语句 看到了 是md5加密后的 这里也是看了wp 才知道特殊MD5 可以被识别为 注入的万能钥匙 ffifdyopmd5 加密后是 276F722736C95D99E921722CF9ED621C转变为字符串 后是 or6 乱码这里就可以实现 注入 所…

定时任务详解

1、定时任务 在公司做项目时&#xff0c;经常遇到要用到定时任务的事情&#xff0c;但是对定时任务不熟练的时候会出现重复任务的情况&#xff0c;不深入&#xff0c;这次将定时任务好好学习分析一下 定时任务的原理 假如我将一个现场通过不断轮询的方式去判断&#xff0c;就…

理解一致性哈希算法

摘要&#xff1a;一致性哈希是什么&#xff0c;使用场景&#xff0c;解决了什么问题&#xff1f; 本文分享自华为云社区《16 张图解 &#xff5c; 一致性哈希算法》&#xff0c;作者&#xff1a;小林coding。 如何分配请求&#xff1f; 大多数网站背后肯定不是只有一台服务器…

文件格式转换

把我的悲惨故事说给大家乐呵乐呵&#xff1a;老板让运营把一些数据以json格式给我&#xff0c;当我看到运营在石墨文档上编辑的时候我人都傻了&#xff0c;我理解运营的艰难&#xff0c;可我也是真的难啊&#xff0c;在石墨文档编辑的眼花缭乱的&#xff0c;很多属性都错乱了(诸…

Sui基金会宣布将从外部做市商处收回1.17亿枚SUI,以支持生态和社区发展

Sui网络是一条突破性的L1区块链&#xff0c;于今年5月推出主网&#xff0c;并因可扩展性和行业领先的吞吐量而备受赞誉&#xff0c;被誉为最出色的区块链网络之一。由于这些$SUI之前已经释放&#xff0c;它们的重新分配不会影响$SUI的流通供应。这些$SUI还包括近日宣布的为Sui流…

[SWPUCTF 2021 新生赛]sql - 联合注入

这题可以参考文章&#xff1a;[SWPUCTF 2021 新生赛]easy_sql - 联合注入||报错注入||sqlmap 这题相比于参考文章的题目多了waf过滤 首先&#xff0c;仍然是网站标题提示参数是wllm 1、fuzz看哪些关键字被过滤&#xff1a;空格、substr、被过滤 2、?wllm-1/**/union/**/selec…