一句话总结:菜就多练。
原题链接:39 组合总和
还是基础的回溯算法的模板,主要需要注意的是回溯递归过程的逻辑。
class Solution {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
backtrack(candidates, target, 0);
return ans;
}
private void backtrack(int[] candidates, int target, int start) {
if (target == 0) {
ans.add(new ArrayList<>(path));
return;
}
for (int i = start; i < candidates.length; ++i) {
if (target - candidates[i] < 0) break;
path.add(candidates[i]);
backtrack(candidates, target - candidates[i], i);
path.removeLast();
}
}
}
原题链接:40 组合总和II
与上一题组合总和类似,但多了一条每个数字在每个组合里仅能使用一次的限制。因此单层回溯的逻辑需要加上一条判断,以实现去重操作。
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> path = new ArrayList<>();
Arrays.sort(candidates);
backtrack(candidates, target, 0, ans, path);
return ans;
}
private void backtrack(int[] candidates, int target, int start, List<List<Integer>> ans, List<Integer> path) {
if (target == 0) {
ans.add(new ArrayList<>(path));
return;
}
for (int i = start; i < candidates.length; ++i) {
if (target - candidates[i] < 0) break;
if (i > start && candidates[i] == candidates[i - 1]) continue;
path.add(candidates[i]);
backtrack(candidates, target - candidates[i], i + 1, ans, path);
path.removeLast();
}
}
}
原题链接:131 分割回文串
相较于前两题,此题涉及到字符串的操作,更加复杂一些,除了常规的回溯及其单层递归逻辑以外还需要判断是否回文串。
class Solution {
List<List<String>> ans = new ArrayList<>();
List<String> sub = new ArrayList<>();
String s;
public List<List<String>> partition(String s) {
this.s = s;
backtrack(0, 0);
return ans;
}
private void backtrack(int i, int start) {
if (i == s.length()) {
ans.add(new ArrayList<>(sub));
return;
}
if (i < s.length() - 1) backtrack(i + 1, start);
String t = s.substring(start, i + 1);
if (check(t)) {
sub.add(t);
backtrack(i + 1, i + 1);
sub.removeLast();
}
}
private boolean check(String s) {
return s.equals(new StringBuffer(s).reverse().toString());
}
}