读思码

日常记录


回溯算法

<p>回溯算法常用来解决以下问题:</p> <ol> <li>排列问题</li> <li>组合问题</li> <li>切割问题:一个字符串按照某种规则有几种切割方式</li> <li>子集问题</li> <li>棋盘问题</li> </ol> <p>套路框架就是遍历决策树 其核心就是 for 循环里面的递归,在递归调用之前做<strong>选择</strong>,在递归调用之后<strong>撤销选择</strong></p> <pre><code>result = [] def backtrack(路径, 选择列表): if 满足结束条件: result.add(路径) return for 选择 in 选择列表: 做选择 backtrack(路径, 选择列表) 撤销选择 </code></pre> <p>做选择和撤销选择的详解</p> <pre><code>for 选择 in 选择列表: # 做选择 将该选择从选择列表移除 路径.add(选择) backtrack(路径, 选择列表) # 撤销选择 路径.remove(选择) 将该选择再加入选择列表</code></pre> <p>不管怎么优化,都符合回溯框架,而且时间复杂度都不可能低于 O(N!),因为穷举整棵决策树是无法避免的。<strong>这也是回溯算法的一个特点,不像动态规划存在重叠子问题可以优化,回溯算法就是纯暴力穷举,复杂度一般都很高。</strong> 注意,add的时候要new,不然是引用,会出问题</p> <pre><code> private static void backtrack(List&lt;Integer&gt; temp, int[] nums) { if (temp.size() == nums.length) { // 这里注意要new result.add(new ArrayList&lt;&gt;(temp)); return; } for (int i = 0; i &lt; nums.length; i++) { if (temp.contains(nums[i])) { continue; } temp.add(nums[i]); backtrack(temp, nums); temp.remove(temp.size()-1); } }</code></pre> <p><a href="https://zhuanlan.zhihu.com/p/93530380" title="参考文章">参考文章</a></p>

页面列表

ITEM_HTML