Leetcode 491.递增子序列

题目:491.递增子序列

初始思路

求自增子序列,不能对原序列进行排序。

代码

  1. var findSubsequences = function (nums) {
  2. let res = []
  3. let path = []
  4. const backtracking = (startIndex) => {
  5. if (path.length > 1) {
  6. res.push([...path])
  7. // 注意这里不要return,要取树上的节点
  8. }
  9. let uesd = []
  10. for (let i = startIndex; i < nums.length; i++){
  11. if ((path.length > 0 && nums[i] < path[path.length - 1]) || uesd[nums[i] + 100]) {
  12. continue
  13. }
  14. // 因为题目给的数字范围是 -100 ~ 100
  15. // 标记为使用过了
  16. uesd[nums[i] + 100] = true
  17. path.push(nums[i])
  18. backtracking(i + 1)
  19. // 回溯
  20. path.pop()
  21. }
  22. }
  23. backtracking(0)
  24. return res
  25. };

感想

  1. 一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置。
  2. 图示
    image.png

Leetcode 46.全排列

题目:46.全排列

初始思路

这题就是排列了,不是组合,不同的顺序代表不同的排列。

代码

  1. var permute = function (nums) {
  2. let res = []
  3. let path = []
  4. const backtracking = (uesd) => {
  5. // 如果路径的长度达到了nums的长度,说明找到了一种排列
  6. if (path.length === nums.length) {
  7. res.push([...path])
  8. return
  9. }
  10. // 因为是排列不是组合,所以是从0开始
  11. for (let i = 0; i < nums.length; i++) {
  12. // path里已经收录的元素,直接跳过
  13. if (uesd[i]) continue
  14. path.push(nums[i])
  15. // 标记为使用过 一个排列里一个元素只能使用一次
  16. uesd[i] = true
  17. backtracking(uesd)
  18. // 回溯
  19. path.pop()
  20. uesd[i] = false
  21. }
  22. }
  23. backtracking([])
  24. return res
  25. };

感想

  1. 首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。
  2. 可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。
  3. image.png

Leetcode 47.全排列 II

题目:47.全排列 II

初始思路

相比上题给的nums里面多了重复的数字,要返回所有不重复的全排列。

代码

  1. var permuteUnique = function (nums) {
  2. let res = []
  3. let path = []
  4. nums.sort((a, b) => a - b)
  5. const backtracking = (used) => {
  6. // 如果路径的长度达到了nums的长度,说明找到了一种排列
  7. if (path.length === nums.length) {
  8. res.push([...path])
  9. return
  10. }
  11. // 因为是排列,所以从0开始
  12. for (let i = 0; i < nums.length; i++){
  13. // used[i - 1] == true 说明同一树枝nums[i - 1]使用过
  14. // used[i - 1] == false 说明同一树层nums[i - 1]使用过
  15. // 如果遇到同一树层nums[i - 1]使用过则直接跳过
  16. if (i > 0 && nums[i] === nums[i - 1] && !used[i - 1]) {
  17. continue
  18. }
  19. // 如果同一树枝nums[i]没使用过开始处理
  20. if (!used[i]) {
  21. used[i] = true
  22. path.push(nums[i])
  23. backtracking(used)
  24. // 回溯
  25. path.pop()
  26. used[i] = false
  27. }
  28. }
  29. }
  30. backtracking([])
  31. return res
  32. };

感想

  1. 在40.组合总和II、90.子集II分别详细讲解了组合问题和子集问题如何去重。
  2. image.png