代码随想录day25|491递增子序列46全排列47全排列II|01笔记

116 阅读3分钟
  • 491递增子序列

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 因为是要找到数组的递增子序列,所以就不能进行排序了。本题的难点在于如何去重。
  • 讲解观后感

  • 首先还是要确认本题的去重方式是同层去重而不是同枝去重。然后可以利用map里记录本层已经使用过的元素。
  • 解题代码

  •     func findSubsequences(nums []int) [][]int {
            ans := make([][]int, 0)
            
            if len(nums) <2 {
                return ans
            }
        
            path := make([]int, 0, len(nums))
            var backtrac func(nums []int, idx int) 
            backtrac = func(nums []int, idx int) {
                if len(path)>1 {
                    tmp := make([]int, len(path))
                    copy(tmp, path)
                    ans = append(ans, tmp)
                }
                used := make(map[int]bool, len(nums))
                for i:=idx;i<len(nums);i++ {
                    if used[nums[i]] {   // 去重
                        continue
                    }
                    if len(path)==0 || nums[i]>=path[len(path)-1] {
                        path = append(path, nums[i])
                        used[nums[i]] = true
                        backtrac(nums, i+1)
                        path = path[:len(path)-1]
                    }
                }
            } 
            backtrac(nums, 0)
            return ans
        }
        
    
  • 46全排列

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 排列问题和组合问题的变化,一个是同层的下一次搜索可以从头开始查找,因为不会出现重复数字,所以不需要考虑去重。但是需要记录同树枝使用过的元素,可以使用map记录使用情况,在回溯函数中传参。
  • 解题代码

  • 使用map记录
  •     func permute(nums []int) [][]int {
            ans := make([][]int, 0)
            path := make([]int, 0, len(nums))
            used := make(map[int]bool, len(nums))
            var backtrac func(nums []int, used map[int]bool)
            backtrac = func(nums []int, used map[int]bool) {
                if len(path)==len(nums) {
                    tmp := make([]int, len(path))
                    copy(tmp, path)
                    ans = append(ans, tmp)
                    return
                }
                for i:=0;i<len(nums);i++ {
                    if !used[nums[i]] {
                        path = append(path, nums[i])
                        used[nums[i]] = true
                        backtrac(nums, used)
                        used[nums[i]] = false
                        path = path[:len(path)-1]
                    }
                }
            }
        
            backtrac(nums, used)
            return ans
        }
    
  • 使用数组记录
  •     var (
            res [][]int
            path  []int
            st    []bool   // state的缩写
        )
        func permute(nums []int) [][]int {
            res, path = make([][]int, 0), make([]int, 0, len(nums))
            st = make([]bool, len(nums))
            dfs(nums, 0)
            return res
        }
        
        func dfs(nums []int, cur int) {
            if cur == len(nums) {
                tmp := make([]int, len(path))
                copy(tmp, path)
                res = append(res, tmp)
            }
            for i := 0; i < len(nums); i++ {
                if !st[i] {
                    path = append(path, nums[i])
                    st[i] = true
                    dfs(nums, cur + 1)
                    st[i] = false
                    path = path[:len(path)-1]
                }
            }
        }
    
  • 47全排列II

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 在基础的全排列中怎增加了重复的元素,于是就要想办法也在同层之中去重。也许可以多用一个used数组再来记录同层的使用情况。
  • 讲解观后感

  • 多使用一个used数组的方式是不对的,因为同枝不同层的去重逻辑是只要不重复使用同一个位置的数字。而同层的逻辑是不能使用同样大小的数字。而且在同层内也不能使用mao存储的方式去重,因为每次遍历都是从开头重来的,所以第一次出现的数字会造成后面所有的数字无法获取。
  • 所以我们还是使用排序后查看前一个数字的方式。这样能够获取重复的数字。
  • 同树层去重逻辑的示意图:
    image.png
  • 出现问题

image.png

  • 问题原因,同层的去重如果使用是是map的逻辑,那么会造成一个used使同层所有后面带相等元素都无法获取。
  • 解决方法,还是使用排序后的去重方式。不排序的仿佛需要处理的东西太多了。
  • 解题代码

  •     func permuteUnique(nums []int) [][]int {
            ans := make([][]int, 0)
            path := make([]int, 0)
            used := make([]bool, len(nums))
            sort.Ints(nums)
            var backtrac func(nums []int, used []bool)
            backtrac = func(nums []int, used []bool) {
                if len(path)==len(nums) {
                    tmp := make([]int, len(path))
                    copy(tmp, path)
                    ans = append(ans, tmp)
                    return
                }
        
                for i:=0;i<len(nums);i++ {
                    if i != 0 && nums[i] == nums[i-1] && !used[i-1] {  // 去重
                        continue
                    }
                   
                    if !used[i] {
                        path = append(path, nums[i])
                        used[i] = true
                        backtrac(nums, used)
                        used[i] = false
                        path = path[:len(path)-1]
                    }
                }
            }
        
            backtrac(nums, used)
            return ans
        }