LeetCode46全排列(回溯入门)

LeetCode46全排列(回溯入门)

首页休闲益智方块排序更新时间:2024-05-11
欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

题目描述

输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

输入:nums = [0,1] 输出:[[0,1],[1,0]]

输入:nums = [1] 输出:[[1]] 个人回溯和46题的理解

解题思路
  1. 终止条件:只要组合的数字达到给定数字的长度,就可以终止了
  2. 路径:就是正在组合的元素,可以用数组表达
编码

public class L0046 { List<List<Integer>> res = new ArrayList<>(); public List<List<Integer>> permute(int[] nums) { // 回溯过程中的重要辅助参数:标记nums数组中有哪些已经使用过 boolean[] used = new boolean[nums.length]; // 回溯过程中的重要辅助参数:路径 int[] path = new int[nums.length]; dfs(nums, used, path, 0); return res; } public void dfs(int[] nums, boolean[] used, int[] path, int depth) { // 终止条件(深度达到) // 搜集:栈入res // 本题的终止条件是一次组合的长度达到数组长度 if (depth==nums.length) { // 搜集结果 // 千万注意:这个path一直在使用中,所以不能把path放入res中,而是path的元素 // res.add(Arrays.stream(path).boxed().collect(Collectors.toList())); List<Integer> list = new ArrayList<>(); for(int val : path) { list.add(val); } res.add(list); return; } // for循环 for (int i=0;i<nums.length;i ) { // 如果当前数字没有用到,就标记,进入path,再做dfs if (!used[i]) { used[i] = true; // 注意,path的下标千万不要用i! // 例如1和2的全排列,在制造[2,1]的时候,i=1,但此时要修改的是path[i], // 所以path的下标应该是depth path[depth] = nums[i]; // 一次递归,深度要加一 dfs(nums, used, path, depth 1); used[i] = false; } } } public static void main(String[] args) { List<List<Integer>> list = new L0046().permute(new int[] {1,2,3}); list.forEach(one -> { Tools.printOneLine(one); }); } }

  1. res用于搜集达到终止条件的记录,也就是数字组合结果
  2. dfs方法就是本次回溯操作的核心方法
  3. 下图红色箭头所指代码就是本题最重要的一行,可见for循环的执行过程中,修改的都是path数组的同一个位置的值,这就是刚才提到的深度至上,只有进入了下面的dfs方法后,深度变化,修改的path数组的位置才会发生变化

  1. used数组用来记录深度调用过程中,那些数字已经被使用了,当前不要再使用
  2. 很多回溯的代码中,用栈对象保持path中的数据,入栈push,出栈pop都是标准操作,但是本题中用char数组,再配合depth,就可以满足需要了,这种原始类型的使用也会带来更好的性能
执行结果

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved