算法练习:回溯

2022/01/02 Algorithm 共 1072 字,约 4 分钟

算法练习:回溯

俗称:穷举、暴力破解

思路

解决一个回溯问题,实际上就是一个决策树的遍历过程。

以全排列为例:

alt

站在当前节点上做决策,可以选择 1 那条树枝,也可以选择 3 那条树枝,因为 2 这个树枝在你身后,已经选择过来。

关键要素:

  • 路径:已经做出的选择。
  • 选择列表:当前可以做的选择。
  • 结束条件:到达决策树底层,无法再做选择的条件。

伪代码框架:

result = []
def backtrack(路径, 选择列表):
    if 结束条件:
        result.add(路径)
        return
    
    for 选择 in 选择列表:
        做选择
        backtrack(路径, 选择列表)
        撤销选择

路径和选择列表:可以直接保存,也可以通过某种方式推算出来

alt

  • 在节点的前序遍历位置,做选择
  • 在节点的后序遍历位置,撤销选择

alt

结束条件就是遍历到树的底层叶子节点,这里也就是选择列表为空的时候

练习

力扣:46. 全排列

class Solution {
    private List<List<Integer>> result;
    private LinkedList<Integer> choose;
    private boolean[] used;

    public List<List<Integer>> permute(int[] nums) {
        result = new LinkedList<>();
        choose = new LinkedList<>();
        used = new boolean[nums.length];

        backtrack(nums, choose, used);

        return result;
    }

    //路径:nums和used组合,获取待路径的列表
    //选择列表:choose
    private void backtrack(int[] nums, LinkedList<Integer> choose, boolean[] used) {
        //结束条件
        if (choose.size() == nums.length) {
            result.add(new LinkedList(choose));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
            if (used[i]) {
                continue;
            }

            //做选择
            choose.add(nums[i]);
            used[i] = true;

            //递归
            backtrack(nums, choose, used);

            //撤销选择
            used[i] = false;
            choose.removeLast();
        }
    }
}

参考

  • https://labuladong.github.io/algo/4/29/105/

Search

    Table of Contents