目录
39.组合总和
解题思路
-
无重复的数组,组合中的元素可以重复使用
-
回溯三步曲
-
同一个集合中使用startIndex,控制for循环的起始位置
-
组合中元素可以重复使用,则单层逻辑处理-递归,使用i,不再是i+1
Java代码
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
backTracking(res, new LinkedList<>(), candidates, target, 0, 0);
return res;
}
//递归
//参数:返回结果 path路径 数组 目标整数 数组中整数之和 开始下标(同一个集合需要下标)
public void backTracking(List<List<Integer>> res, LinkedList<Integer> path, int[] candidates, int target, int sum, int startIndex) {
//终止条件
if (sum > target) {
return;
}
if (sum == target) {
res.add(new ArrayList<>(path));
return;
}
//单层逻辑
for (int i = startIndex; i < candidates.length; i++) {
//剪枝
if (sum + candidates[i] > target) {
break;
}
//处理
sum += candidates[i];
path.add(candidates[i]);
backTracking(res, path, candidates, target, sum, i); //startIndex 为i可以重复选择元素
//回溯
sum -= candidates[i];
path.removeLast();
}
}
}
40.组合总和II
解题思路
-
与组合之和不同之处,集合中有重复的元素,但是集合中的元素在组合中不可重复使用
-
回溯三步曲
-
同一个集合使用startIndex
-
组合中不能包含重复的组合,所以需要去重
-
去重是指:树层的去重,强调一下,树层去重,数组需要进行排序;而不是指树枝的去重
-
Java代码
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(candidates);
backTracking(res, new LinkedList<Integer>(), candidates, target, 0, 0);
return res;
}
//确定返回值和参数
public void backTracking(List<List<Integer>> res, LinkedList<Integer> path, int[] candidates, int target, int sum, int start) {
//终止条件
if (sum > target) {
return;
}
if (sum == target) {
res.add(new ArrayList<>(path));
}
//单层逻辑
//树层需要去重(横向遍历时 candidates[i] == candidates[i-1]):可通过use数组标记来去重,也可以通过start索引去重
//树枝无需去重
for (int i = start; i < candidates.length; i++) {
//剪枝
if (sum + candidates[i] > target) {
break;
}
//去重 树层相同的元素 直接跳过
if (i > start && candidates[i] == candidates[i-1]) {
continue;
}
//处理
sum += candidates[i];
path.add(candidates[i]);
backTracking(res, path, candidates, target, sum, i+1); //注意 condidates中数字每个只能使用一次,需要获取下一个数字
//回溯
sum -= candidates[i];
path.removeLast();
}
}
}
131.分割回文串
解题思路
-
切割问题,有不同的切割方式
-
判断是否为回文
-
切割与组合类似
-
组合:在选取a之后,在bcde中选取第二个,选取b之后在cde中选取下一个
-
切割:在切割a之后,在bcde中切割第二段,切割b之后在cde中切割下一段
-
-
使用startIndex作为切割线
Java代码
class Solution {
List<List<String>> res = new ArrayList<>();
Deque path = new LinkedList<>();
public List<List<String>> partition(String s) {
backTracking(s, 0);
return res;
}
//确定返回值和参数
public void backTracking(String s, int start) {
//终止条件
//如果start大于等于s的长度,说明已切割到最后,需要退出
if (start >= s.length()) {
res.add(new ArrayList<>(path));
}
//单层逻辑
//start为切割线,判断[start, i +1]是否为回文,是的话加入path
for(int i = start; i < s.length(); i++) {
if (isPalindrome(s, start, i)) {
String str = s.substring(start, i + 1);
path.add(str);
} else {
continue;
}
backTracking(s, i + 1); //注意 不能重复切割,所以切割线要后移一位
//回溯
path.removeLast();
}
}
//判断字符串是否为回文 双指针
private 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;
}
}