39. 组合总和
给你一个 无重复元素的整数数组
candidates
和一个目标整数target
,找出candidates
中可以使数字和为目标数target
的 所有 **不同组合,并以列表形式返回。你可以按 任意顺序 返回这些组合。
输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。
回溯三部曲:
-
确定参数和返回值:返回值为void,参数为数组candidates,目标和target,记录sum,选取开始的索引startIndex
-
终止条件:
sum==target
将结果添加到relsut中返回 -
单层搜索逻辑
处理节点、递归、回溯
其中剪枝处理,如果sum + candidates[i] > target就会不符合条件
class Solution {
List<List<Integer>> reslut=new ArrayList<>();
List<Integer> res=new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates); // 先进行排序
trackbacking(candidates,target,0,0);
return reslut;
}
public void trackbacking(int[] candidates,int target,int sum,int startIndex){
if(sum==target){
reslut.add(new ArrayList<>(res));
return;
}
for(int i=startIndex;i<candidates.length && sum + candidates[i] <= target;i++){
res.add(candidates[i]);
trackbacking(candidates,target,sum+candidates[i],i);
res.remove(res.size()-1);
}
}
}
40. 组合总和 II
给定一个候选人编号的集合
candidates
和一个目标数target
,找出candidates
中所有可以使数字和为target
的组合。
candidates
中的每个数字在每个组合中只能使用 一次 。
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
**集合(数组candidates)有重复元素,但还不能有重复的组合,**所以这道题的关键是去重
回溯三部曲:
-
参数和返回值:返回值为void,参数为candidates,target,sum,startIndex
-
递归终止条件:
sum==target
-
单层搜索逻辑
为了进行去重我们定义了一个boolean数组 used,首先将数组填充为false
这里首先需要考虑去重
candidates[i]==candidates[i-1]&&!used[i-1]
跳过本次循环处理节点:处理节点是需要将used[i]设置为true表明这个数出现过
递归
回溯:回溯需要将used[i]设置为false,在进行下一层处理
class Solution {
List<List<Integer>> reslut=new ArrayList<>();
List<Integer> path=new ArrayList<>();
boolean[] used;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
used = new boolean[candidates.length];
Arrays.fill(used,false);
Arrays.sort(candidates);
trackbacking(candidates,target,0,0);
return reslut;
}
public void trackbacking(int[] candidates,int target,int sum,int startIndex){
if(sum==target){
reslut.add(new ArrayList<>(path));
return;
}
for(int i=startIndex;i<candidates.length&&sum + candidates[i] <= target;i++){
if(i>0&&candidates[i]==candidates[i-1]&&!used[i-1]){
continue;
}
used[i]=true;
sum+=candidates[i];
path.add(candidates[i]);
trackbacking(candidates,target,sum,i+1);
used[i]=false;
path.remove(path.size()-1);
sum-=candidates[i];
}
}
}
Arrays.fill(arrayname,value) 方法,用于数组填充
131. 分割回文串
给你一个字符串
s
,请你将 **s
**分割成一些子串,使每个子串都是 回文串 。返回s
所有可能的分割方案。回文串 是正着读和反着读都一样的字符串。
输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个.....。
切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段.....。
回溯三部曲:
-
参数和返回值:返回值为void,参数为字符串s,strtindex用来记录分割点
-
终止条件:如果切割点strtindex>=s.length()
-
单层搜索逻辑
首先需要判断截取字符串是否为回文,如果为回文用substring截取字符串并添加到path当中
回溯
递归
判断是否为回文:只需两个指针,一个从起点开始遍历,一个从末尾开始遍历,如果字符不相等则为false,若相等则为true
class Solution {
List<List<String>> reslut=new ArrayList<>();
List<String> path=new ArrayList<>();
public List<List<String>> partition(String s) {
trackbacking(s,0);
return reslut;
}
public void trackbacking(String s,int starIndex){
if(starIndex>=s.length()){
reslut.add(new ArrayList<>(path));
return;
}
for(int i=starIndex;i<s.length();i++){
if(isPalindrome(s,starIndex,i)){
String str=s.substring(starIndex,i+1);
path.add(str);
}else{
continue;
}
trackbacking(s,i+1);
path.remove(path.size()-1);
}
}
//判断回文
private boolean isPalindrome(String s,int startIndex,int endIndex){
for(int i=startIndex,j=endIndex;i<j;i++,j--){
if(s.charAt(i)!=s.charAt(j)){
return false;
}
}
return true;
}
}