自己写的代码
version1
class Solution {
List<List<Integer>> res=new LinkedList();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
int sum=0;
LinkedList<Integer> track=new LinkedList();
backTrack(candidates,target,track,sum);
return res;
}
public void backTrack(int[] candidates,int target,LinkedList<Integer> track,int sum){
if(sum==target){
res.add(new LinkedList(track));
return;
}
for(int i=0;i<candidates.length;i++){
sum+=candidates[i];
track.add(candidates[i]);
backTrack(candidates,target,track,sum);
track.removeLast();
sum-=candidates[i];
}
}
}
编译都没通过,报错,track.add(candidates[i]);
处栈溢出。
之后知道:严格把条件限制为sum==target
,而有些情况下,sum<target<(candidates[i]+sum)
。即sum在没加上candidates
数组中的某一个值时是没到给的目标值target
的,但加上之后又大于。就是没有sum==target
,就会一直加。最后栈溢出。
version2
class Solution {
List<List<Integer>> res=new LinkedList();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
int sum=0;
LinkedList<Integer> track=new LinkedList();
backTrack(candidates,target,track,sum);
return res;
}
public void backTrack(int[] candidates,int target,LinkedList<Integer> track,int sum){
if(sum==target){
res.add(new LinkedList(track));
return;
}
for(int i=0;i<candidates.length;i++){
if(sum<=target){
sum+=candidates[i];
track.add(candidates[i]);
backTrack(candidates,target,track,sum);
track.removeLast();
sum-=candidates[i];
}
}
}
}
通过案例23/170
原因:没有去掉相同的组合。如输入[2,3,6,7] 7
,输出为
[[2,2,3],[2,3,2],[3,2,2],[7]]
,但预期输出为[[2,2,3],[7]]
存在的问题:如何去掉汉相同的元素。
出现这个问题的原因分析:遍历数组元素时,一开始的元素a往前找可以组合为目的值的元素b,假如,a+b=target,就结束了。然后遍历a的后一个元素,以此类推。到以b开始遍历时,b又往前找元素,此时就会找到a,又返回b+a=target,与前一种情况只是顺序不同。
解决方法:每次遍历时,当前值不要往它前面找其他元素,而只往后。
实施:尝试使用全局变量i
控制,一旦满足sum==target
就重新让i=0
,行不通。
参考别人的解决方法
在backTrack
方法中加入变量start
,i
起使于start
,在回溯/回归算法中就能将上一次的值传到下一次。
代码
class Solution {
List<List<Integer>> res=new LinkedList();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
// int sum=0;
LinkedList<Integer> track=new LinkedList();
backTrack(candidates,target,track,0,0);
return res;
}
public void backTrack(int[] candidates,int target,LinkedList<Integer> track,int sum,int start){
if(sum==target){
res.add(new LinkedList(track));
return;
}
for(int i=start;i<candidates.length;i++){
if(sum<=target){
sum+=candidates[i];
track.add(candidates[i]);
backTrack(candidates,target,track,sum,i);
track.removeLast();
sum-=candidates[i];
}
}
}
}
代码中可以改进之处
在for循环中加入了if判断(而且是for中要执行的语句都放在了if语句中),目的是想要满足一定条件才执行。此时可以把if移出for循环
即代码改为如下:
class Solution {
List<List<Integer>> res=new LinkedList();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
// int sum=0;
LinkedList<Integer> track=new LinkedList();
backTrack(candidates,target,track,0,0);
return res;
}
public void backTrack(int[] candidates,int target,LinkedList<Integer> track,int sum,int start){
if(sum==target){
res.add(new LinkedList(track));
return;
}
if(sum>target) return;
for(int i=start;i<candidates.length;i++){
sum+=candidates[i];
track.add(candidates[i]);
backTrack(candidates,target,track,sum,i);
track.removeLast();
sum-=candidates[i];
}
}
}
可以减小运行时间
总结
如果想要将一个参数的值传到下一次调用,可以将这个参数放在方法的参数列表中。【一般使用于回溯/回归算法值中】
backTrack()
| ……
| String str=”rqm“
| ……
|(回溯)
|______backTrack()
如图所示,想要在第二个的backTrack
中使用第一个backTrack
中改变了的参数值str
,就可以将str
作为backTrack
的参数,从而可以在第二个backTrack
中操作str
。