目录
题目1: 组合总和
- 题目链接:39. 组合总和
1- 思路
回溯三部曲
- 本题目中,同一
path
下的元素可以重复使用,因此在回溯过程中传入的startIndex
参数不需要进行 +1 去重操作。 - 1. 回溯函数参数及返回值
candidates
:数组startIndex
:控制回溯树上同层元素去重——>通过i = startIndex
实现target
:目标值nowSum
:当前和
- 2. 回溯终止&&结果收集
- 如果 nowSum > target 则终止
- 如果 nowSum == target 收集结果
- 3. 回溯逻辑
- 因为本题在同一个 path 上的回溯无需去重,因此 在递归过程 i 无需 +1
- 因此每次 对 nowSum 和 path 进行更新
- 回溯 nowSum 和 path
2- 题解
⭐ 组合总和 ——题解思路
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
backTracing(candidates,0,target,0);
return res;
}
public void backTracing(int[] candidates,int startIndex,int target,int nowSum){
if(nowSum>target){
return ;
}
if(nowSum==target){
res.add(new ArrayList(path));
return;
}
for(int i = startIndex ; i < candidates.length;i++){
nowSum += candidates[i];
path.add(candidates[i]);
backTracing(candidates,i,target,nowSum);
nowSum-=candidates[i];
path.remove(path.size()-1);
}
}
}
题目2: 组合总和II
- 题目链接:40. 组合总和 II
1- 思路
本题区别于 组合总和 的点在于,此时要对重复的元素进行去重的逻辑
- 本质上是树层去重
难点在于去重逻辑
- 因为是树层去重,所以去重逻辑在 for 循环中
- 其中为什么是
if( i > 0 && nums[i]==nums[i-1] && used[i-1] ==0)
used[i-1] ==0
是因为 该步骤实现的是书层去重,如果是used[i-1] ==1
的话比如相邻元素[1,1,2] 此时会使得在同一路径上 会去重 1 ,此时是不符合题目逻辑的,因为题目如果 target是4实际上 1 1 2 这个组合是符合逻辑的,因此做的是 树层 去重 而不是 树枝 去重
2- 题解
⭐组合总和 II ——题解思路
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
int[] used = new int[candidates.length];
Arrays.fill(used,0);
Arrays.sort(candidates);
backTracing(candidates,target,used,0,0);
return res;
}
public void backTracing(int[] candidates,int target,int[] used,int nowSum,int startIndex){
// 终止
if(nowSum > target){
return ;
}
if(nowSum == target){
res.add(new ArrayList(path));
return ;
}
// 单层
for(int i = startIndex;i<candidates.length;i++){
if(i>0 && candidates[i] == candidates[i-1] && used[i-1] == 0){
continue;
}
path.add(candidates[i]);
used[i] = 1;
nowSum+=candidates[i];
backTracing(candidates,target,used,nowSum,i+1);
nowSum-=candidates[i];
path.removeLast();
used[i] = 0;
}
}
}
题目3: 分割回文串
- 题目链接:131. 分割回文串
1- 思路
该回溯的方法实际上是对字符串进行分割,回溯的目标是找分割点
区别在于 for 循环的具体回溯过程
- 如果 String 在回溯过程中,子串满足 回文条件(通过自定义判断是否回文)
- 则 分割字符串 ——> path 收集结果 ——> 递归 ——> 回溯
- 否则
continue
2- 题解
⭐分割回文串 ——题解思路
class Solution {
List<String> path = new ArrayList<>();
List<List<String>> res= new ArrayList<>();
public List<List<String>> partition(String s) {
backTracing(s,0);
return res;
}
public void backTracing(String s,int startIndex){
if(startIndex==s.length()){
res.add(new ArrayList(path));
return ;
}
// 单层回溯
for(int i = startIndex;i<s.length();i++){
if(isPlainDrome(s,startIndex,i)){
String str = s.substring(startIndex,i+1);
path.add(str);
backTracing(s,i+1);
path.remove(path.size()-1);
}else{
continue;
}
}
}
public boolean isPlainDrome(String s,int left,int right){
for(;left<right;left++,right--){
if(s.charAt(left)!=s.charAt(right)){
return false;
}
}
return true;
}
}