组合总和
力扣连接:39. 组合总和(中等)
1.回溯的方法
本题是 集合里元素可以用无数次,那么和组合问题的差别 其实仅在于 startIndex上的控制
图解步骤
关键点:
- 本题元素为可重复选取的。
递归代码
class Solution {
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> tmp = new LinkedList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
back(candidates, target, 0);
return result;
}
public void back(int[] nums, int target, int startIndex){
if(target==0){
result.add(new ArrayList<>(tmp));
return;
}
for(int i = startIndex; i<nums.length && target>0; i++){
tmp.add(nums[i]);
target -= nums[i];
back(nums, target, i);
target += nums[i];
tmp.removeLast();
}
}
}
组合总和 II
力扣连接:40. 组合总和 II(中等)
1.回溯的方法
本题开始涉及到一个问题了:去重。
图解步骤
关键点:
- 去重的是同一树层上的 “使用过” ,同一树枝上的都是一个组合里的元素,不用去重。
递归代码
class Solution {
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> tmp = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
back(candidates, target, 0, new int[candidates.length]);
return result;
}
public void back(int[] nums, int target, int startIndex, boolean[] used){
if(target==0){
result.add(new ArrayList<>(tmp));
return;
}
for(int i = startIndex; i<nums.length && target>0; i++){
// used[i - 1] == 1,说明同一树枝candidates[i - 1]使用过
// used[i - 1] == 0,说明同一树层candidates[i - 1]使用过
// 要对同一树层使用过的元素进行跳过
if(i>0 && nums[i]==nums[i-1] && used[i-1]==0){
continue;
}
tmp.add(nums[i]);
target -= nums[i];
used[i] = 1;
back(nums, target, i+1, used);
used[i] = 0;
target += nums[i];
tmp.removeLast();
}
}
}
分割回文串
力扣连接:131. 分割回文串(中等)
切割问题的回溯搜索的过程和组合问题的回溯搜索的过程是差不多的。
图解步骤
关键点:
来看看在递归循环中如何截取子串呢?
- 在for (int i = startIndex; i < s.size(); i++)循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串。
代码
class Solution {
List<List<String>> result = new ArrayList<>();
LinkedList<String> tmp = new LinkedList<>();
public List<List<String>> partition(String s) {
backtracking(s, 0);
return result;
}
public void backtracking(String s, int startIndex){
if(startIndex == s.length()){
result.add(new ArrayList<>(tmp));
return;
}
for(int i = startIndex; i<s.length(); i++){
if(isPalindrome(s, startIndex, i)){
tmp.add(s.substring(startIndex, i+1));
}else{
continue;
}
backtracking(s, i+1);
tmp.removeLast();
}
}
//判断是否是回文串
private boolean isPalindrome(String s, int startIndex, int end) {
for (int i = startIndex, j = end; i < j; i++, j--) {
if (s.charAt(i) != s.charAt(j)) {
return false;
}
}
return true;
}
// public boolean isPalindrome(String s, int startIndex, int endIndex){
// String sub = s.substring(startIndex, endIndex+1);
// int[] next = new int[sub.length()];
// getNext(next, sub);
// return next[sub.length()-1]==sub.length()-1;
// }
// public void getNext(int[] next, String s){
// next[0] = 0;
// int j = 0;
// for(int i = 1; i<s.length(); i++){
// //不相同的情况
// while(j>0 && s.charAt(i)!=s.charAt(j)){
// j = next[j-1];
// }
// //相同的情况
// if(s.charAt(i)==s.charAt(j)){
// j++;
// }
// //赋值
// next[i] = j;
// }
// }
}