39.组合总和
解题思路:
class Solution {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> path = new LinkedList<>(); // 因为path设计到经常修改,所以用LinkedList
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates); // 先进行排序
backTracking(candidates, target, 0);
return ans;
}
public void backTracking(int[] candidates, int target, int startIndex){ // startIndex为了避免输出重复结果
if(target == 0){ // 回溯的终止条件
ans.add(new ArrayList<>(path));
return;
}
for(int i = startIndex; i < candidates.length; i++){
if(candidates[i] > target) return;
path.add(candidates[i]);
backTracking(candidates, target - candidates[i], i);
path.remove(path.size() - 1);
}
}
}
40.组合总和II
题目链接:40. 组合总和 II - 力扣(LeetCode)
解题思路:
class Solution {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> path = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
// used数组是为了记录哪个元素使用过了。
boolean[] used = new boolean[candidates.length];
Arrays.fill(used, false);
// 这个排序是为了后续去重方便,不然输出的结果中会有重复解出现。因为数组中的数字是不唯一的
Arrays.sort(candidates);
backTracking(candidates, target, used, 0);
return ans;
}
public void backTracking(int[] candidates, int target, boolean[] used, int startIndex){
if(target == 0){ // 结束条件
ans.add(new ArrayList<>(path));
return;
}
for(int i = startIndex; i < candidates.length; i++){
if(candidates[i] > target) return;
if(used[i] == true) continue;
// 这里的去重是为了去除[1,1,2,5] target = 8 这种数组中的两组1 2 5的情况
if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) {
continue;
}
used[i] = true;
path.add(candidates[i]);
backTracking(candidates, target - candidates[i], used, i);
used[i] = false;
path.remove(path.size() - 1);
}
}
}
131.分割回文串
题目链接:131. 分割回文串 - 力扣(LeetCode)
解题思路:
首先是错误代码: backTracking里面的逻辑没有理清楚
class Solution {
List<List<String>> ans = new ArrayList<>();
List<String> path = new LinkedList<>();
public List<List<String>> partition(String s) {
backTracking(s, 0);
return ans;
}
public void backTracking(String s, int startIndex){
if(startIndex >= s.length()){ //结束条件
ans.add(new ArrayList<>(path));
return;
}
for(int i = startIndex; i < s.length(); i++){
//开始剪枝
for(int j = i + 1; j <= s.length(); j++){
if(!ishw(s.substring(i,j))) continue;
path.add(s.substring(i,j));
backTracking(s, j);
path.remove(path.size() - 1);
}
}
}
public boolean ishw(String s){
int i = 0, j = s.length() - 1;
while(i < j){
if(s.charAt(i) == s.charAt(j)){
i++;
j--;
}
else return false;
}
return true;
}
}
关键部分如下:
// public void backTracking(String s, int startIndex){
// if(startIndex >= s.length()){ //结束条件
// ans.add(new ArrayList<>(path));
// return;
// }
for(int i = startIndex; i < s.length(); i++){
//开始剪枝
for(int j = i + 1; j <= s.length(); j++){
if(!ishw(s.substring(i,j))) continue;
path.add(s.substring(i,j));
backTracking(s, j);
path.remove(path.size() - 1);
}
}
// }
我在这里套了两层for循环,为了得到符合条件的回文字符串,这样显然是错误的,错误的根本在于没有搞清楚startIndex到底是用来干嘛的。因为本题目中的要求是进行拆分,也就是说startIndex这个起始位置在下一次拆分的时候必须是分割的起点,但是如果像上述两层for循环来做的话,只不过是让起点从startIndex开始而已,这个思路显然是错误的。
正确的代码如下:
class Solution {
List<List<String>> ans = new ArrayList<>();
List<String> path = new LinkedList<>();
public List<List<String>> partition(String s) {
backTracking(s, 0);
return ans;
}
public void backTracking(String s, int startIndex){
if(startIndex >= s.length()){ //结束条件
ans.add(new ArrayList<>(path));
return;
}
for(int i = startIndex; i < s.length(); i++){
//如果是回文子串,则记录
if (ishw(s.substring(startIndex, i + 1))) {
String str = s.substring(startIndex, i + 1);
path.add(str);
} else {
continue;
}
//起始位置后移,保证不重复
backTracking(s, i + 1);
path.remove(path.size() - 1);
}
}
public boolean ishw(String s){
int i = 0, j = s.length() - 1;
while(i < j){
if(s.charAt(i) == s.charAt(j)){
i++;
j--;
}
else return false;
}
return true;
}
}