力扣39.组合总和
题目链接:https://leetcode.cn/problems/combination-sum/
思路
和216题组合3思路大致一致,区别就是组合内元素可以重复,这就涉及到了startIndex的选取,由于可以重复,所以递归时startIndex可以由本身也就是i开始。
还有一个我自己实现时的问题,没有想到当sum>target时要返回,如果不进行返回,即使数组和已经大于目标值还是会一直递归。
剪枝
**对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历。**代码如下:
for (int i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++)
完整代码
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
backtracking(candidates,target,0,0);
return res;
}
public void backtracking(int[] candidates,int target,int sum,int startIndex){
if(sum > target) return;
if(target == sum){
res.add(new ArrayList<>(path));
return;
}
for (int i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++) {
path.add(candidates[i]);
sum += candidates[i];
backtracking(candidates,target,sum,i);
sum -= candidates[i];
path.removeLast();
}
}
}
力扣40.组合总和2
题目链接:https://leetcode.cn/problems/combination-sum-ii/
思路
去重逻辑还是看卡哥的比较清晰。https://programmercarl.com/
完整代码
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
boolean[] used;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
used = new boolean[candidates.length];
Arrays.fill(used,false);
Arrays.sort(candidates);
backtracking(candidates,target,0,0);
return res;
}
public void backtracking(int[] candidates,int target,int sum,int startIndex){
if(sum > target) return;
if(sum == target){
res.add(new ArrayList<>(path));
}
for (int i = startIndex; i < candidates.length; i++) {
if(i > 0 && candidates[i] == candidates[i-1] && !used[i-1]){
continue;
}
sum += candidates[i];
path.add(candidates[i]);
used[i] = true;
backtracking(candidates,target,sum,i+1);
sum -= candidates[i];
used[i] = false;
path.removeLast();
}
}
}
力扣131.分割回文串
题目链接:https://leetcode.cn/problems/palindrome-partitioning/
思路
1.使用startIndex来分割字符。什么时候收获结果?
当startIndex遍历到字符串末尾时。
2.在一个for循环里,判断(startIndex,i)是否是回文,因为startIndex是固定的,i一个个遍历过去,发现是回文就加入deque中。**substring()方法是左闭右开区间。**发现不是回文,就跳过,i直接++。
3.然后进入递归,从i+1开始。别忘记移除回溯的最后的字符。
完整代码
class Solution {
List<List<String>> res = new ArrayList<>();
Deque<String> deque = new LinkedList<>();
public List<List<String>> partition(String s) {
backtracking(s,0);
return res;
}
public void backtracking(String s,int startIndex){
if(startIndex >= s.length()){
res.add(new ArrayList<>(deque));
return;
}
for(int i = startIndex;i < s.length();i++){
if(isPalindrome(s,startIndex,i)){
String str = s.substring(startIndex,i+1);
deque.addLast(str);
}else{
continue;
}
backtracking(s,i+1);
deque.removeLast();
}
}
public boolean isPalindrome(String s,int start,int end){
for(int i = start,j = end;i < j;i++,j--){
if(s.charAt(i) != s.charAt(j)){
return false;
}
}
return true;
}
}