组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
- 所有数字(包括 target)都是正整数。
- 解集不能包含重复的组合。
示例 1:
- 输入:candidates = [2,3,6,7], target = 7,
- 所求解集为: [ [7], [2,2,3] ]
示例 2:
- 输入:candidates = [2,3,5], target = 8,
- 所求解集为: [ [2,2,2,2], [2,3,3], [3,5] ]
回溯三部曲:
- 递归函数参数:
数组,目标值,和,开始位置
void backTracking(int[] candidates, int target,int sum,int startIndex)
- 递归终止条件
sum>target 不满足条件了直接走下次循环
sum==target 刚好满足,记录
- 单层搜索的逻辑
for (int i = startIndex; i < candidates.length; i++) {
integerList.add(candidates[i]);
sum+=candidates[i];
//candidates 中的数字可以无限制重复被选取,所以下次是从i开始
backTracking(candidates,target,sum,i);
//回溯
sum-=candidates[i];
integerList.removeLast();
}
代码
private static List<List<Integer>> list = new ArrayList<>();
private static LinkedList<Integer> integerList = new LinkedList<>();
public static List<List<Integer>> combinationSum(int[] candidates, int target) {
backTracking(candidates,target,0,0);
return list;
}
private static void backTracking(int[] candidates, int target,int sum,int startIndex) {
if (sum>target){
return;
}
if (sum==target){
list.add(new ArrayList<>(integerList));
}
for (int i = startIndex; i < candidates.length; i++) {
integerList.add(candidates[i]);
sum+=candidates[i];
backTracking(candidates,target,sum,i);
sum-=candidates[i];
integerList.removeLast();
}
}
组合总和II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明: 所有数字(包括目标数)都是正整数。解集不能包含重复的组合。
- 示例 1:
- 输入: candidates = [10,1,2,7,6,1,5], target = 8,
- 所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
和上一个差不多
重点:解集不能包含重复的组合
这里需要一个boolean[] used 用来标记数组元素是否使用
而且需要先对数组排序,因为不能重复组合,但相同元素是可以取到的
代码
private static List<List<Integer>> list = new ArrayList<>();
private static LinkedList<Integer> integerList = new LinkedList<>();
static boolean[] used;
public static List<List<Integer>> combinationSum2(int[] candidates, int target) {
used = new boolean[candidates.length];
Arrays.fill(used, false);//填充数组
Arrays.sort(candidates);
backTracking(candidates,target,0,0);
return list;
}
private static void backTracking(int[] candidates, int target,int sum,int startIndex) {
if (sum>target){
return;
}
if (sum==target){
list.add(new ArrayList<>(integerList));
}
for (int i = startIndex; i < candidates.length; i++) {
//这里是同一树层的去重,而不是不同数层的去重
//排序后,同一数层,取相同元素时,会continue
if (i>0&&candidates[i]==candidates[i-1]&&!used[i - 1]){
continue;
}
integerList.add(candidates[i]);
sum+=candidates[i];
used[i]=true;
backTracking(candidates,target,sum,i+1);
sum-=candidates[i];
used[i]=false;
integerList.removeLast();
}
}
分割回文串
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例: 输入: “aab” 输出: [ [“aa”,“b”], [“a”,“a”,“b”] ]
究极难,看了题解也是似懂非懂
List<List<String>> list = new ArrayList<>();
Deque<String> deque = new LinkedList<>();
public List<List<String>> partition(String s) {
backTracking(s, 0);
return list;
}
private void backTracking(String s, int startIndex) {
if (startIndex >= s.length()) {
list.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();
}
}
private 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;
}