参考文献链接:代码随想录
本人代码是Java版本的,如有别的版本需要请上代码随想录网站查看。
39. 组合总和
解题思路
这道题目和昨天的组合总和类似,不过这道题目是可以选择重复元素,所以在for循环条件上会有一些改变。并且这道题目不是i像昨天的必须是k个元素相加为某值,这道题多少个元素都行,所以递归终止只需要看sum的值和target的值大小即可。
代码示例
class Solution {
private Set<List<Integer>> result = new HashSet<>();
private List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
backtracking(target,candidates,0,0);
return new ArrayList(result);
}
public void backtracking(int target,int[] candidates,int sum,int index){
if(sum == target){
result.add(new ArrayList<>(path));
return;
}
if(sum > target){
return;
}
for(int i = index;i < candidates.length;i++){
path.add(candidates[i]);
backtracing(target,candidates,sum + candidates[i],i);
path.remove(path.size() - 1);
}
}
}
40.组合总和II
解题思路
这道题目跟上一道思路上差不多,只要限制一下不要对同一元素再次使用即可。
但是这道题还有一个易错的,就是去重。
比如一组数[1,1,7],target = 8
那么第一个1和7,第二个1和7都能满足目标,所以要去重。
所以我们要有一个boolean数组,每次使用过的元素记录一下true。
if(i>0 && candidates[i] == candidates[i - 1] && !used[i - 1]){
continue;
}
当前元素和前一元素相同时我们就要考虑是否重复(前提数组先排序)。
那么!used[i - 1]是什么?
其实我们有两种可能candidates[i] == candidates[i - 1]。
第一种在树枝上,比如一组数[1,1,7],target = 9,这种情况下1+1+7=9,那么此时1和1都要用,不能去重。
第二种就是树层上比如一组数[1,1,7],target = 8,这种情况两个1要去1个。
那么我们就要看!used[i - 1],当前一个元素是true,那就说明前一个也被使用了,则是第一种情况。
如果前一个元素是false,说明是树层之间重复了,这种就要continue掉。
代码示例
class Solution {
private Set<List<Integer>> result = new HashSet<>();
private List<Integer> path = new ArrayList<>();
private boolean[] used;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
used = new boolean[candidates.length];
Arrays.fill(used,false);
Arrays.sort(candidates);
backtracking(target,candidates,0,0);
return new ArrayList(result);
}
public void backtracking(int target,int[] candidates,int sum,int index){
if(sum == target){
result.add(new ArrayList<>(path));
return;
}
if(sum > target){
return;
}
for(int i = index;i < candidates.length;i++){
if(i>0 && candidates[i] == candidates[i - 1] && !used[i - 1]){
continue;
}
path.add(candidates[i]);
used[i] = true;
backtracking(target,candidates,sum + candidates[i],i+1);
path.remove(path.size() - 1);
used[i] = false;
}
}
}
131.分割回文串
解题思路
思路跟前几道差不多,我们可以用一个StringBuilder保存字符串,当有回文字符串出现就加入paths中并且开启递归寻找剩余字符串能否拆分为回文字符串。
对这道题来说我一开始想的是通过两个下标去拆分他们找出每一个都是回文字符串,但其实不用拆分,我们只需要for循环一个一个字符去加,出现回文字符串开启递归去寻找下一个回复字符串即可。
代码示例
class Solution {
private List<String> path = new ArrayList<>();
private List<List<String>> result = new ArrayList<>();
public List<List<String>> partition(String s) {
backtracking(s,0,new StringBuilder());
return result;
}
public void backtracking(String s,int startIndex,StringBuilder sb){
if(startIndex == s.length()){
result.add(new ArrayList<>(path));
return;
}
for(int i = startIndex;i < s.length();i++){
sb.append(s.charAt(i));
if(isMoslems(new String(sb))){
path.add(new String(sb));
backtracking(s,i + 1,new StringBuilder());
path.remove(path.size() - 1);
}
}
}
public boolean isMoslems(String s){
int left = 0;
int right = s.length() - 1;
while(left < right){
if(s.charAt(left) != s.charAt(right)){
return false;
}
left++;
right--;
}
return true;
}
}