算法总结--回溯

近期本人在leetcode上刷了不少回溯的题目,leetcode回溯专题能刷的题都刷了,现在对回溯做一个简单的总结。

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。 

不把它的定义拿过来总觉得此文缺点什么,所以我从百度百科回溯算法摘抄了上面这段文字。通俗来讲,回溯是一种尝试多种可能的搜索过程,当满足条件时一直走下去,当不满足时回过头来尝试其他路径,不撞南墙不回头。

什么时候使用回溯?

当一个问题需要多种可能的结果时,并且此时即使暴力编写也无从下手,请试试回溯,例如排列组合问题。

回溯代码框架

回溯算法是有框架的,首先它是一个递归,需要设置递归终止条件;递归函数中找出下一步所有可能路径,然后对每个可能递归调用,调用前设置,调用后清除设置。

大致如下:

void backtrace() {
    if (终止条件) {
        处理结果
        return;
    }
    for (下一步所有可能) {
        剪枝
        设置变量
        backtrace(); // 递归
        清除变量设置  // 回溯
    }
}

当下一步所有可能只有1种时,此时就是纯粹的递归,没的选择一条路走下去就是,此时用不着回溯。

剪枝是为了提升效率,明知不可能就不要做了,比如排列中数字1已经使用了,下一步就不要再使用了。在列举所有可能的过程中考虑剪枝条件也是可以的。

回溯能够解决哪类问题?

排列:

46. 全排列:无重复数字全排列

47. 全排列 II:有重复数字全排列

剑指 Offer 38. 字符串的排列 & 面试题 08.08. 有重复字符串的排列组合:有重复字符全排列

面试题 08.07. 无重复字符串的排列组合

784. 字母大小写全排列

1079. 活字印刷:重复字符串中任意字符的所有排列

面试题 08.09. 括号 & 22. 括号生成:打印n对括号的所有合法组合

组合:

77. 组合:返回 1 ... n 中所有可能的 k 个数的组合

216. 组合总和 III:找出所有相加之和为 n 的 k 个数的组合

39. 组合总和:和为target的数的组合(数可重复使用)

40. 组合总和 II:和为target的数的组合(数不可重复使用)

17. 电话号码的字母组合:数字2-9对应3-4个字母

1780. 判断一个数字是否可以表示成三的幂的和:k个数的组合

1286. 字母组合迭代器

子集、分割:

131. 分割回文串:分割成回文串

842. 将数组拆分成斐波那契序列:将数字字符串拆分成斐波那契序列

93. 复原 IP 地址:将数字字符串复原成IP地址

1593. 拆分字符串使唯一子字符串的数目最大

78. 子集 & 面试题 08.04. 幂集:输出所有子集

306. 累加数:与斐波那契类似

路径:

797. 所有可能的路径

980. 不同路径 III

332. 重新安排行程

棋盘:

51. N 皇后 & 面试题 08.12. 八皇后

37. 解数独

79. 单词搜索

猜你喜欢

转载自blog.csdn.net/hbuxiaoshe/article/details/115320295
今日推荐