力扣:全排列(回溯算法)
问题:给定一个 没有重复 数字的序列,返回其所有可能的全排列
全排列问题实际可以看作是树形结构
而dfs算法在树形结构中的应用就是回溯算法。
接下来详细解释回溯算法的思想:
如图所示:在本题中,树形结构的根节点为空,根节点的第一个子节点通过遍历找到[1],继续遍历找到[1]的子节点[2],[2]的子节点[3]。此时我们可以设置一次遍历结束的标志是遍历的次数与数组的长度一致。
状态:每一个节点都表示了在求解问题上的不同阶段。如[1][2]可能代表[1]-->[2],也可能代表[1][2][3][2].
因此,深度优先遍历在回到上一层状态时需要“状态重置”。
实际编程时,需要遍历次数depth,已经选择的数path(选择的数从根节点到叶子节点,故path为栈类型),以及判断数是否被选择的boolean类型tOf。
public class Main { public List<List<Integer>> permute(int[] nums) { int numsLength = nums.length; // numsLength为nums长度 List<List<Integer>> res = new ArrayList<>(); // 返回值 Deque<Integer> path = new ArrayDeque<>(); // path类型为Stack类型,系统推荐使用Deque。 // path用来存放每一次遍历结果 boolean[] tOf = new boolean[numsLength]; // boolean数组对应nums中数字是否被遍历 dfs(nums,numsLength,0,path,tOf,res); return res; } private void dfs(int[] nums, int numsLength, int depth, Deque<Integer> path, boolean[] tOf, List<List<Integer>> res) { // 遍历结束条件 if (numsLength == depth) { res.add(new ArrayList<>(path)); return; } // for循环遍历 for (int i = 0; i < numsLength; i++) { // 判断nums中数字是否被遍历到 if (tOf[i]) { continue; } // 若未被遍历 path.addLast(nums[i]); // 将遍历到的nums[i]放入path尾部 tOf[i] = true; // 将对应tof置为true,表示已遍历 dfs(nums,numsLength,depth+1,path,tOf,res); // 继续向下搜索 path.removeLast(); // 假设[1][2][3]回溯,返回上一层[1][2]。但是如何继续返回[1]节点呢 // 这时候tof[1]为true,代表nums[1]已被遍历,继续回撤。 tOf[i] = false; } } }
上述为力扣题库47题解加上个人感想,若有不同的想法或做法欢迎评论交流。
下一题讨论为在数组存在重复元素情况下的全排列。