跟III的区别在于候选元素从原来的数字换成具体的数组了,其他的大概逻辑没有变,还有就是startIndex穿进去的时候不用+1(因为可以重复添加自身)
class Solution {
private List<List<Integer>> resList = new ArrayList<>();
private List<Integer> res = new ArrayList<>();
private void backtracking(int[] candidates , int n, int startIndex, int sum){
if(sum > n){
return;
}
if(sum == n){
resList.add(new ArrayList<>(res));
return;
}
for(int i = startIndex; i < candidates.length; i++){
res.add(candidates[i]);
sum += candidates[i];
backtracking(candidates, n, i, sum);
sum -= candidates[i];
res.remove(res.size() - 1);
}
}
public List<List<Integer>> combinationSum(int[] candidates, int target) {
backtracking(candidates, target, 0, 0);
return resList;
}
}
- 潜在的剪枝:对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历。(一定要排序!!!)
40.组合总和II
- 这题难点是去重,用一个数组used标记数字是否用过的状态;
- 重点是一定要排序!!!否则continue的条件就不一定会成立了
class Solution {
private List<List<Integer>> resList = new ArrayList<>();
private List<Integer> res = new ArrayList<>();
private boolean used[];
private void backtracking(int[] candidates , int n, int startIndex, int sum){
if(sum > n){
return;
}
if(sum == n){
resList.add(new ArrayList<>(res));
return;
}
for(int i = startIndex; i < candidates.length; i++){
if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) {
continue; // 跳过和前一个数字相同的数字
}
used[i] = true;
res.add(candidates[i]);
sum += candidates[i];
backtracking(candidates, n, i + 1, sum);
sum -= candidates[i];
res.remove(res.size() - 1);
used[i] = false;
}
}
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
used = new boolean[candidates.length];
Arrays.sort(candidates);
backtracking(candidates, target, 0, 0);
return resList;
}
}
- 对数组排序:Arrays.sort(candidates);
class Solution {
private List<List<Integer>> resList = new ArrayList<>();
private List<Integer> res = new ArrayList<>();
private boolean used[];
private void backtracking(int[] candidates , int n, int startIndex, int sum){
if(sum > n){
return;
}
if(sum == n){
resList.add(new ArrayList<>(res));
return;
}
for(int i = startIndex; i < candidates.length; i++){
if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) {
continue; // 跳过和前一个数字相同的数字
}
used[i] = true;
res.add(candidates[i]);
sum += candidates[i];
backtracking(candidates, n, i + 1, sum);
sum -= candidates[i];
res.remove(res.size() - 1);
used[i] = false;
}
}
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
used = new boolean[candidates.length];
Arrays.sort(candidates);
backtracking(candidates, target, 0, 0);
return resList;
}
}
- Arrays.sort(candidates):对数组进行排序;
- if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) {
continue; // 跳过和前一个数字相同的数字
}
131. ***分割回文串
重点是如何分割的问题,重点看下图:
class Solution {
private boolean isPalindrome(String s){
int i = 0, j = s.length() - 1;
while(i < j){
if(s.charAt(i) != s.charAt(j)){
return false;
}
i++;
j--;
}
return true;
}
private List<List<String>> resList = new ArrayList<>();
private List<String> res = new ArrayList<>();
// private StringBuilder sb = new StringBuilder();
private void backtracking(String s, int startIndex){
if(startIndex >= s.length()){
// res.add(sb.toString());
resList.add(new ArrayList<>(res));
return;
}
for(int i = startIndex; i < s.length(); i++){
if(isPalindrome(s.substring(startIndex,i + 1))){
res.add(s.substring(startIndex,i + 1));
}else{
continue;
}
backtracking(s, i + 1);
res.remove(res.size() - 1);
}
}
public List<List<String>> partition(String s) {
backtracking(s, 0);
return resList;
}
}
- 这里注意用startIndex模拟切割线,注意s.substring(startIndex,i + 1))传入的是i + 1,因为是左闭右开区间。
- resList.add(new ArrayList<>(res));老问题了,不然没办法正确村结果。