参考资料:
https://programmercarl.com/0039.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C.html
39. 组合总和
题目描述:
给你一个 无重复元素 的整数数组 candidates
和一个目标整数 target
,找出 candidates
中可以使数字和为目标数 target
的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates
中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target
的不同组合数少于 150
个。
示例 1:
输入:candidates =[2,3,6,7],
target =7
输出:[[2,2,3],[7]] 解释: 2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。 7 也是一个候选, 7 = 7 。 仅有这两种组合
思路分析:
1.先排序,方便剪枝操作
2. 递归时,起始下标不用 i+1。因为元素可以重复选取
代码实现:
class Solution {public List<List<Integer>> combinationSum(int[] candidates, int target) {List<List<Integer>> res=new ArrayList<>();//排序Arrays.sort(candidates);backTracking(res,new ArrayList<>(),candidates,target,0,0);return res;}private void backTracking(List<List<Integer>> res,List<Integer> path,int[] candidates,int target,int sum,int startIndex){if(target==sum){res.add(new ArrayList<>(path));return;}for(int i=startIndex;i<candidates.length;i++){if(sum+candidates[i]>target) break;//剪枝path.add(candidates[i]);backTracking(res,path,candidates,target,sum+candidates[i],i);path.remove(path.size()-1);}}
}
40. 组合总和 II
题目描述:
给定一个候选人编号的集合 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates =[10,1,2,7,6,1,5]
, target =8
, 输出: [ [1,1,6], [1,2,5], [1,7], [2,6] ]
思路分析:
理解题意:集合不能重复,但集合中可以有数值相同的元素
关键:采用used数组标记,避免相同元素作为起始元素。
if(i>0 && candidates[i]==candidates[i-1] && !used[i-1]){
continue;
}
代码实现:
class Solution {List<List<Integer>> res=new ArrayList<>();List<Integer> path=new LinkedList<>();boolean[] used;//标记数组int sum=0;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);return res;}public void backTracking(int[] candidates,int target,int startIndex){if(sum==target){res.add(new LinkedList<>(path));}for(int i=startIndex;i<candidates.length;i++){if(sum+candidates[i]>target) break;//因为数组已经排好序if(i>0 && candidates[i]==candidates[i-1] && !used[i-1]){continue;}used[i]=true;sum+=candidates[i];path.add(candidates[i]);backTracking(candidates,target,i+1);used[i]=false;sum-=candidates[i];path.removeLast();}}
}
131. 分割回文串
题目描述:
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是 回文串 。返回 s
所有可能的分割方案。
示例 1:
输入:s = "aab" 输出:[["a","a","b"],["aa","b"]]
思路分析:
注意单层递归逻辑
代码实现:
//回溯 参考:https://www.programmercarl.com/0131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC
class Solution {List<List<String>> lists=new ArrayList<>();Deque<String> deque=new LinkedList<>();public List<List<String>> partition(String s) {backTracking(s,0);return lists;}public void backTracking(String s,int startIndex){if(startIndex >= s.length()){//到叶子节点了,收集结果lists.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 startIndex,int end){//左闭右闭for(int i=startIndex,j=end;i<j;i++,j--){if(s.charAt(i)!=s.charAt(j)) return false;}return true;}
}