46. 全排列

46. 全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

题解(回溯)

回溯

回溯问题实际上是遍历一棵决策树的过程,把整棵树遍历一遍,收集节点上的答案,就能得到所有的合法答案。

站在回溯树的一个节点上,只需要思考 3 个问题

  1. 「路径」,记录已经做过的选择
  2. 「选择列表」,表示当前可以做出的选择
    1. 前序位置,做选择
    2. 进入下一层决策树
    3. 后序位置,撤销选择
  3. 「结束条件」,遍历到树的底层叶子节点
public List<List<Integer>> res = new LinkedList<>(); // 记录结果
public LinkedList<Integer> track = new LinkedList<>(); // 记录路径
public List<List<Integer>> permute(int[] nums) {
    backtrack(nums);
    return res;
}
// 回溯
public void backtrack(int[] nums) {
    // 结束条件,base case,到达叶子节点
    if (track.size() == nums.length) {
        // 找出一个全排列,退出。不能直接add(track),track引用的对象一直在变化,最后track为空,导致res添加的所有track也全都为空。
        res.add(new LinkedList<>(track));
        return;
    }
    // 选择列表
    for (int i = 0; i < nums.length; i++) {
        // 已存在的路径排除,避免重复使用
        if (track.contains(nums[i])) continue;
        track.add(nums[i]); // 前序位置,做选择
        backtrack(nums); // 进入下一层决策树
        track.removeLast(); // 后序位置,撤销选择
    }
}

避免重复选择

  1. 使用集合的 contains() 方法判断
  2. 使用 used数组 标记还可以被选择的元素

元素个数为k的排列

如果题目不求全排列,让求元素个数为k的排列?

修改backtrack 函数的结束条件,仅收集第 k 层的节点值。

// 结束条件
if (track.size() == k) {
    res.add(new LinkedList<>(track));
    return;
}

你可能感兴趣的:(算法,算法,java)