Leetcode 491.递增子序列
题目:491.递增子序列
初始思路
代码
var findSubsequences = function (nums) {let res = []let path = []const backtracking = (startIndex) => {if (path.length > 1) {res.push([...path])// 注意这里不要return,要取树上的节点}let uesd = []for (let i = startIndex; i < nums.length; i++){if ((path.length > 0 && nums[i] < path[path.length - 1]) || uesd[nums[i] + 100]) {continue}// 因为题目给的数字范围是 -100 ~ 100// 标记为使用过了uesd[nums[i] + 100] = truepath.push(nums[i])backtracking(i + 1)// 回溯path.pop()}}backtracking(0)return res};
感想
- 一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置。
- 图示

Leetcode 46.全排列
题目:46.全排列
初始思路
代码
var permute = function (nums) {let res = []let path = []const backtracking = (uesd) => {// 如果路径的长度达到了nums的长度,说明找到了一种排列if (path.length === nums.length) {res.push([...path])return}// 因为是排列不是组合,所以是从0开始for (let i = 0; i < nums.length; i++) {// path里已经收录的元素,直接跳过if (uesd[i]) continuepath.push(nums[i])// 标记为使用过 一个排列里一个元素只能使用一次uesd[i] = truebacktracking(uesd)// 回溯path.pop()uesd[i] = false}}backtracking([])return res};
感想
- 首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。
- 可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。

Leetcode 47.全排列 II
题目:47.全排列 II
初始思路
相比上题给的nums里面多了重复的数字,要返回所有不重复的全排列。
代码
var permuteUnique = function (nums) {let res = []let path = []nums.sort((a, b) => a - b)const backtracking = (used) => {// 如果路径的长度达到了nums的长度,说明找到了一种排列if (path.length === nums.length) {res.push([...path])return}// 因为是排列,所以从0开始for (let i = 0; i < nums.length; i++){// used[i - 1] == true 说明同一树枝nums[i - 1]使用过// used[i - 1] == false 说明同一树层nums[i - 1]使用过// 如果遇到同一树层nums[i - 1]使用过则直接跳过if (i > 0 && nums[i] === nums[i - 1] && !used[i - 1]) {continue}// 如果同一树枝nums[i]没使用过开始处理if (!used[i]) {used[i] = truepath.push(nums[i])backtracking(used)// 回溯path.pop()used[i] = false}}}backtracking([])return res};
感想
- 在40.组合总和II、90.子集II分别详细讲解了组合问题和子集问题如何去重。

