回溯

参考:https://zhuanlan.zhihu.com/p/302415065

关于回溯

回溯是递归的“副产品”,并非高效算法,通过剪枝可以跳过非必要的搜索。

回溯算法能解决如下问题:

  1. 组合问题:N个数里面按一定规则找出k个数的集合;
  2. 排列问题:N个数按一定规则全排列,有几种排列方式;
  3. 切割问题:一个字符串按一定规则有几种切割方式;
  4. 子集问题:一个N个数的集合里有多少符合条件的子集;
  5. 棋盘问题:N皇后,解数独等等。

注:「组合是不强调元素顺序的,排列是强调元素顺序」,即组合无序,排列有序。

回溯函数的伪代码模板

    def backtracking(self, 参数列表):
        # 定义递归出口
        if 终止条件:
            保存结果
            return
        for i in range(n):
            处理
            self.dfs(参数)
            处理回退

以组合问题举例

一句话总结:for循环横向遍历,递归纵向遍历,回溯不断调整结果集。

例题:力扣77题:给定两个整数n和k,返回1...n中所有可能的k个数的组合。思路如下图:

代码如下:

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

    def combine(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: List[List[int]]
        """
        nums = [i for i in range(1, n+1)]
        sizeN = len(nums)
        self.dfs(nums, sizeN, k, 0, [])
        return self.res

    def dfs(self, nums, sizeN, k, begin, temp):
        # 定义递归出口:长度为k
        if len(temp) == k:
            self.res.append(temp)
        for i in range(begin, sizeN):
            if len(temp) > k:
                break
            # 递归
            self.dfs(nums, sizeN, k, i+1, temp+[nums[i]])

上述例题是在一个集合中求组合,需要用到“begin”这个变量来控制for循环的起始位置。

那么对于组合问题,什么时候需要此变量呢?

如果是一个集合来求组合,就需要begin,例如:力扣39、40、77等题;

如果是多个集合取组合,各个集合之间相互不影响,那么就不需要begin,例如:力扣17题。

做题中总结的一个模板

class Solution():
    # 返回值,定义为全局变量
    def __init__(self):
        self.res = []

    def function(self, string):
        n = len(string)
        temp = []
        visit = [0 for _ in range(n)]
        self.dfs(string, temp, visit, n)
        return self.res

    def dfs(self, string, temp, visit, n):
        # 定义递归出口
        if len(temp) == len(string):
            self.res.append("".join(temp))
        else:
            # for循环横向遍历
            for i in range(n):
                # 当且仅当当前字符未被访问
                if not visit[i]:
                    # 用temp记录当前访问
                    temp.append(string[i])
                    visit[i] = 1
                    # 递归调用,纵向遍历
                    self.dfs(string, temp, visit, n)
                    # 回退
                    temp.pop(-1)
                    visit[i] = 0
posted @ 2020-11-23 16:19  人间烟火地三鲜  阅读(369)  评论(0编辑  收藏  举报