leetcode之回溯backtracing专题2
来源:互联网 发布:阿里巴巴比淘宝贵2016 编辑:程序博客网 时间:2024/05/04 06:07
46 Permutations
输入一个不重复的数组 ,写出这个数组的排列,不能重复。
例如 输入nums=[1,2,3],输出
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
思路:可以看到 第0位(从左开始数)有nums.length个数字可以选择:1,2,3,在第0位确定以后,第1位有nums.length-1个数字可以选择,例如p[0] = 1,p[1]只可能为2 或者3。所以重要的是记录哪些下标的元素已经被选择过。
public class Solution { private boolean[] p;//记录选中过的下标 private List<List<Integer>> list; public List<List<Integer>> permute(int[] nums) { int[] newarray=new int[nums.length];//存放选中的数字 p = new boolean[nums.length]; list = new ArrayList<List<Integer>>(); robot(0,newarray,nums); return list; } public void robot(int idx,int[] newarray,int[] nums){ if(idx>=nums.length){ List<Integer> l = new ArrayList<Integer>(); for(int i=0;i<newarray.length;i++){ l.add(newarray[i]); } list.add(l); return; } for(int i=0;i<nums.length;i++){ if(p[i]==false){ newarray[idx]=nums[i]; p[i]=true; robot(idx+1,newarray,nums); p[i]=false; } } }}
47 Permutations II
输入一个重复的数组 ,写出这个数组的排列,不能重复。
例如输入 [1,1,2] 输出
[
[1,1,2],
[1,2,1],
[2,1,1]
]
思路:这与46的区别是输入的数组中有重复的数字。如果按照46的思路做,会出现重复的结果。我们先按照46的来做一下吧。用”数字(下标)”这种方式表示数组元素:1(0) 1(1) 2(2)。这样才能把相同的数字区分开来。为了方便,我们先将输入的数组排序。按照46的思路得到以下组合:
1(0) 1(1) 2(2)
1(0) 2(2) 1(1)
1(1) 1(0) 2(2)
1(1) 2(2) 1(0)
2(2) 1(0) 1(1)
2(2) 1(1) 1(0)
重点标记的是重复的元素。分析一下。第0位可以选择的元素有 nums[0], nums[1], nums[2],但是当已经选择nums[0]之后,再遇到nums[1]=nums[0]的时候,nums[1]是不能选择的,否则就重复了。所以第0位可以选择的元素有 nums[0], nums[2]。每一位都是,判断nums[idx]能不能选择标准是nums[idx-1]=nums[idx]是否为true。
这个判断怎么加呢?下面记录一下我自己犯过的错。
处理情况1
for(int i=0;i<nums.length;i++){ if(p[i]==false){ newarray[idx]=nums[i]; p[i]=true; robot(idx+1,newarray,nums); p[i]=false; for (int j = i + 1; j < nums.length; j++){ if (nums[j] != nums[j - 1]) { i = j - 1; break; } } } }
每到一个位置,先选择一个元素,再处理下一个元素和前面的元素是否相同。这里判断的时候没有考虑前面的元素是否会选中,可能会有多余的操作。更重要的是没有处理如果重复元素是最后一个元素怎么处理。失败用例:[1,1]。
for(int i=0;i<nums.length;i++){ if(p[i]==false){ newarray[idx]=nums[i]; p[i]=true; robot(idx+1,newarray,nums); p[i]=false; int j = i + 1; for (; j < nums.length; j++){ if (nums[j] != nums[j - 1]) { i = j - 1; break; } } if(j==nums.length){ break; } } }
改成这样就对了。但是这样代码不够优雅。
处理情况2
for(int i=0;i<nums.length;i++){ if(p[i]==false && (i==0 || (nums[i]!=newarray[idx]))){ newarray[idx]=nums[i]; p[i]=true; robot(idx+1,newarray,nums); p[i]=false; } }
因为newarray[idx]记录了上一次选择的值,所以想到只要判断这次的候选值nums[i]和newarray[idx]不同就好了。这次的错误是因为i==0的判断是有误的。因为不一定每次都是nums[0]是第一个被选中的。例如当第0位选择nums[0],在选第2位的时候第一个被选中的一定是nums[1] ,所以这里应该用一个boolean变量表示本次是不是对idx已经选过一个值了。
boolean selected = false; for(int i=0;i<nums.length;i++){ if(p[i]==false && (!selected || (nums[i]!=newarray[idx]))){ selected = true; newarray[idx]=nums[i]; p[i]=true; robot(idx+1,newarray,nums); p[i]=false; } }
处理情况3
接着我还用了一种方式处理。使用了一个单独的变量记录在选择idx的候选值时候,上一个选择的值。
int preNum = -1; boolean selected = false; for(int i=0;i<nums.length;i++){ if(p[i]==false && (selected==false || (nums[i]!=preNum))){ selected = true; preNum = nums[i]; newarray[idx]=nums[i]; p[i]=true; robot(idx+1,newarray,nums); p[i]=false; } }
总结:大概可以在编程的时候行不通。一定是一定可以才可以。在backtracing中最重要的是理解每一步的状态。
- leetcode之回溯backtracing专题2
- leetcode之回溯backtracing专题1
- leetcode之回溯backtracing专题3
- leetcode之回溯backtracing专题4
- leetcode之回溯backtracing专题5
- LeetCode之Backtracing题目汇总
- Backtracing
- 《剑指offer》之回溯法专题
- Hamiltonian Cycle (backtracing: 2^n)
- LeetCode Combinations Problem using backtracing and DFS
- LeetCode 39,40,46,47,78,90 回溯法专题
- 搜索专题之素数环之回溯法
- 【LeetCode】常用算法之回溯法
- leetcode回溯
- 专题2之栈
- leetCode解题报告之Candy(简单回溯)
- LeetCode 回溯算法 backtracking
- leetcode 回溯法 模板
- Linux下如何查看版本信息
- Spring源码分析之BeanPostProcessor接口和BeanFactoryPostProcessor接口方法不执行原因分析
- 记一个关于volatile作状态标志的很奇怪的问题
- Collecting Bugs(POJ-2096)
- Together项目IOS平台开发04
- leetcode之回溯backtracing专题2
- 最短路径
- 数据结构和算法的选择
- MySQL的安装与配置
- Java Web 实现 QQ第三方登录
- python 使用cx_oracle
- MySQL+tomcat9数据库连接池
- MySQL如何选择合适的存储引擎
- 登陆注册(续章)