回溯_20230413

Posted xccx-0824

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回溯_20230413相关的知识,希望对你有一定的参考价值。

90.子集II

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

  • 输入: [1,2,2]
  • 输出: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]

解题思路:

通过回溯法遍历出子集,保证res不包含该path的情况下,将path添加进res中(此处应注意要使用new ArrayList<>(path),否则res所有元素用的是同一块内存会一起变化)。要明确子集不是全排列,与后续的题目有所不同

为了防止出现重复子集的情况,有以下几种方法

  • 对nums数组先进行排序,在某一位置出现过某一数字之后,此后该位置不会再出现该数字,即nums[i] == nums[i - 1]的情况可以直接跳过,且此法可以避免把[1, 2, 3]和[2, 1, 3]当成不同子集的情况(后者通过在下一层的backTracking中指定后续数字必须往上一层的后面取(index + 1),故后者根本不会出现)
  • 在加入res前对path进行转换校验(耗时耗力)

491.递增子序列

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。

示例:

  • 输入: [4, 6, 7, 7]
  • 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]

解题思路:

要注意此题与90.子集II的不同之处在于,本题是要找出递增子序列,不能对数组排序。通过res保存最终结果和path保存过程结果,当path.size() >= 2时即可加入结果。

去重本题使用HashSet,在每一层的backTracking中都设置一个set来存储当前层数出现过的数字,保证在index位置处相同的数字只能出现一次,否则continue。同样可以通过if (res.contains(path))的方法实现去重

46.全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

  • 输入: [1,2,3]
  • 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

解题思路:

该题已明确数组没有重复数字,且因为是全排列问题,自然无需考虑结果去重问题。res记录最终结果,path记录每一个元素,当path的大小与数组相同时说明满足条件可以加入res。但本题需要注意,相同的数字不能重复使用,可以通过boolean[] used来记录数字的使用情况,也可以通过path.contains(nums[i])来判定有无重复(因为数字没有重复所以可以使用此法)

47.全排列 II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

  • 输入:nums = [1,1,2]
  • 输出: [[1,1,2], [1,2,1], [2,1,1]]

示例 2:

  • 输入:nums = [1,2,3]
  • 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

解题思路:

通过一个res记录结果,path记录过程

该题与46.全排列的不同之处在于,数字序列包含重复数字。那么便无法通过path.contains(nums[i])来判定有无重复。此处去重可以通过以下两种方法

  • 通过HashSet来判定在该轮backTracking中是否出现过
  • 事先对数组进行排序,此后nums[i + 1] == nums[i]便直接跳过

同时结合boolean[] used记录下数组中每个位置的数字的使用情况,使用过则跳过直至所有数字都使用为止

131. 分割回文串-回溯算法 (leetcode)

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

返回 s 所有可能的分割方案。

 

代码:

class Solution:
    def __init__(self):
        self.res = []

    def partition(self, s: str) -> List[List[str]]:
        
        self.helper(s,[])
        return self.res

    def helper(self,part_of_s,answerList):
        if not part_of_s:
            self.res.append(answerList)
        for i in range(1,len(part_of_s)+1):
            if part_of_s[:i] == part_of_s[:i][::-1]:
                self.helper(part_of_s[i:],answerList + [part_of_s[:i]])

 思考:

  1. 回溯算法重要的就是回溯,回溯就是把上一步的操作抹去

    a) 在79题单词搜索里体现为:  visited[ i ][ j ] = True;  visted[ i ][ j ] = False

    b)在本题里体现为递归时的变量传递: 不改变当前的anserList 直接传递到下一步 answerList + [part_of_s[:i]],这样循环运行完了以后,answer在本步骤还是没有改变,也不需要抹去上一步操作。

以上是关于回溯_20230413的主要内容,如果未能解决你的问题,请参考以下文章

java学习日记20230413-LinkedList和ArrayList比较

DFS回溯只在递归基回溯————leetcode112

回溯算法_ BackTracking

leetcode_401_Binary Watch_回溯法_java实现

力扣_中级算法_树和图_4~6题_和_回溯算法_第1题

131. 分割回文串-回溯算法 (leetcode)