代码随想录算法训练营第二十九天 | 491. 递增子序列、46. 全排列、47. 全排列 II

78 阅读2分钟

491. 递增子序列

代码随想录文章讲解

回溯+使用set去重

class Solution:
    def findSubsequences(self, nums: List[int]) -> List[List[int]]:
        res = []
        path = []
        
        def _backtracking(start_index, nums):
            nonlocal res
            nonlocal path
            
            if len(path) >= 2:
                res.append(path[:])
                
            usage_list = set()
            for i in range(start_index, len(nums)):
                # not increasing subsequence or already used in this level 
                if path and nums[i] < path[-1] or nums[i] in usage_list: 
                    continue
                path.append(nums[i])
                usage_list.add(nums[i])
                _backtracking(i+1, nums)
                path.pop()
        
        _backtracking(0, nums)
        return res

46. 全排列

代码随想录文章讲解

回溯

  • 如果num已经在path中,我们不取这个num
  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了
class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        path = []
        
        def _backtracking(nums):
            nonlocal res
            nonlocal path
            if len(path) == len(nums):
                res.append(path[:])
                return
            
            for num in nums:
                if num in path:
                    continue
                path.append(num)
                _backtracking(nums)
                path.pop()
        
        _backtracking(nums)
        return res

47. 全排列 II

代码随想录文章讲解

回溯+使用set和counter去重

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        res = []
        path = []
        count = Counter(nums)
        
        def _backtracking(nums):
            nonlocal res
            nonlocal path
            nonlocal count
            
            if len(path) == len(nums):
                res.append(path[:])
                return
            
            used_set = set()
            for num in nums:
                if count[num] == 0 or num in used_set:
                    continue
                    
                used_set.add(num)
                count[num] -= 1
                path.append(num)
                _backtracking(nums)
                count[num] += 1
                path.pop()
        
        _backtracking(nums)
        return res

回溯+使用排序去重

  • 还要强调的是去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了

  • 如果要对树层中前一位去重,就用used[i - 1] == false (前一位已经完成了回溯)

  • 如果要对树枝前一位去重用used[i - 1] == true (前一位没有完成回溯)

  • 对于排列问题,树层上去重和树枝上去重,都是可以的,但是树层上去重效率更高!

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        # res用来存放结果
        if not nums: return []
        res = []
        used = [0] * len(nums)
        def backtracking(nums, used, path):
            # 终止条件
            if len(path) == len(nums):
                res.append(path.copy())
                return
            for i in range(len(nums)):
                if not used[i]:
                    if i > 0 and nums[i] == nums[i-1] and not used[i-1]:
                        continue
                    used[i] = 1
                    path.append(nums[i])
                    backtracking(nums, used, path)
                    path.pop()
                    used[i] = 0
                    
        # 记得给nums排序
        backtracking(sorted(nums),used,[])
        return res