当前位置:   article > 正文

代码随想录 day29 第七章 回溯算法part05

代码随想录 day29 第七章 回溯算法part05

  • 491.递增子序列
  • 46.全排列
  • 47.全排列 II

1. 递增子序列

关联 leetcode 491.递增子序列

本题和大家刚做过的 90.子集II 非常像,但又很不一样,很容易掉坑里。

  • 思路

    • 不能改变原数组顺序
      • 不能先排序
    • 去重
      • 同一层去重
      • 树枝上可以有重复元素
    • 新元素添加条件
      • 大于等于当前次收集数组最右元素
        • value > array[right]
  • 题解

    1. func findSubsequences(nums []int) [][]int {
    2. rets := make([][]int, 0)
    3. ret := make([]int, 0) //从左到右一次递增
    4. var backtracking func(nums []int, startIdx int)
    5. backtracking = func(nums []int, startIdx int) {
    6. //append rets
    7. if len(ret) > 1 {
    8. tmp := make([]int, len(ret))
    9. copy(tmp, ret)
    10. rets = append(rets, tmp)
    11. }
    12. //the map to record if the value used
    13. usedMap := make(map[int]bool)
    14. for i := startIdx; i < len(nums); i++ {
    15. curVal := nums[i]
    16. // 当前层用过了
    17. if usedMap[curVal] {
    18. continue
    19. }
    20. // 取到的数 < 最右的数
    21. if len(ret) > 0 && curVal < ret[len(ret)-1] {
    22. continue
    23. }
    24. usedMap[curVal] = true
    25. ret = append(ret, curVal)
    26. backtracking(nums, i+1)
    27. ret = ret[:len(ret)-1]
    28. }
    29. }
    30. backtracking(nums, 0)
    31. return rets
    32. }

2. 全排列

关联 leetcode 46.全排列

  • 思路

    • 排列开始要考虑顺序了
      • 【1,2】和【2,1】是两个结果
      • 处理排列问题就不用 startIndex 了
      • 需要用一个 used 数组来标记元素的使用
        • 全排列,所有元素都要使用到
    • 收割点
      • 叶子节点处
      • 单层循环的 ret 里面收集的元素数量 == nums 包含的元素数量
        • 取完了这次的全排列
  • 题解

    1. func permute(nums []int) [][]int {
    2. rets := make([][]int, 0)
    3. ret := make([]int, 0)
    4. used := make([]bool, len(nums))
    5. var backtracking func(nums []int, used []bool)
    6. backtracking = func(nums []int, used []bool) {
    7. if len(ret) == len(nums) { //完成了该轮全排列收集
    8. tmp := make([]int, len(ret))
    9. copy(tmp, ret)
    10. rets = append(rets, tmp)
    11. }
    12. for i := 0; i < len(nums); i++ {
    13. if used[i] {//该元素已经收集过了, 收集下一个
    14. continue
    15. }
    16. used[i] = true//收集新元素
    17. ret = append(ret, nums[i])
    18. backtracking(nums, used)//回溯
    19. ret = ret[:len(ret)-1]
    20. used[i] = false
    21. }
    22. }
    23. backtracking(nums, used)
    24. return rets
    25. }

3. 全排列 II

关联 leetcode 47.全排列 II

  • 思路

    • 在上一道题的基础上,增加去重
      • 同一层去重
        • used[i-1]==false
        • 在一个 for 里面的元素去重
      • 树枝去重
        • used[i-1] == true
        • 会多出一些树枝衍生无用操作
    • 一定要加上 used[i - 1] == false或者used[i - 1] == true,因为 used[i - 1] 要一直是 true 或者一直是false 才可以,而不是 一会是true 一会又是false。 所以这个条件要写上
      • used[i-1] 去重
        • 要一直维持同一种 方案:
          • 树层去重
          • 树枝去重
  • 题解

    1. func permuteUnique(nums []int) [][]int {
    2. rets := make([][]int, 0)
    3. ret := make([]int, 0)
    4. used := make([]bool, len(nums))
    5. sort.Ints(nums)
    6. var backtracking func(nums []int, curLen int)
    7. backtracking = func(nums []int, curLen int) {
    8. if curLen == len(nums) { //完成了该轮全排列收集
    9. tmp := make([]int, len(ret))
    10. copy(tmp, ret)
    11. rets = append(rets, tmp)
    12. }
    13. for i := 0; i < len(nums); i++ {
    14. // used[i - 1] == true,说明同一树枝nums[i - 1]使用过
    15. // used[i - 1] == false,说明同一树层nums[i - 1]使用过
    16. // 一定要 used[i-1] 这个判断
    17. if i > 0 && nums[i] == nums[i-1] && !used[i-1] {
    18. continue
    19. }
    20. if !used[i] { //该元素已经收集过了, 收集下一个
    21. used[i] = true //收集新元素
    22. ret = append(ret, nums[i])
    23. backtracking(nums, curLen+1) //回溯
    24. ret = ret[:len(ret)-1]
    25. used[i] = false
    26. }
    27. }
    28. }
    29. backtracking(nums, 0)
    30. return rets
    31. }

    4. 题外话

    • 树层上对前一位去重非常彻底,效率很高,树枝上对前一位去重虽然最后可以得到答案,但是做了很多无用搜索

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/319398
推荐阅读
相关标签
  

闽ICP备14008679号