# LeetCode刷题笔记（16）-BacktrackingⅣ

## 39、组合求和

given candidate set [2, 3, 6, 7] and target 7,
A solution set is:
[[7],[2, 2, 3]]

public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> combinations = new ArrayList<>();
backtracking(new ArrayList<>(), combinations, 0, target, candidates);
return combinations;
}

private void backtracking(List<Integer> tempCombination, List<List<Integer>> combinations,
int start, int target, final int[] candidates) {

if (target == 0) {
return;
}
for (int i = start; i < candidates.length; i++) {
if (candidates[i] <= target) {
backtracking(tempCombination, combinations, i, target - candidates[i], candidates);
tempCombination.remove(tempCombination.size() - 1);
}
}
}

总结：这道题属于比较经典的回溯问题，基本上就是这样的流程


## 40、含有相同元素的组合求和

For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> combinations = new ArrayList<>();
Arrays.sort(candidates);
backtracking(new ArrayList<>(), combinations, new boolean[candidates.length], 0, target, candidates);
return combinations;
}

private void backtracking(List<Integer> tempCombination, List<List<Integer>> combinations,
boolean[] hasVisited, int start, int target, final int[] candidates) {

if (target == 0) {
return;
}
for (int i = start; i < candidates.length; i++) {
if (i != 0 && candidates[i] == candidates[i - 1] && !hasVisited[i - 1]) {
continue;
}
if (candidates[i] <= target) {
hasVisited[i] = true;
backtracking(tempCombination, combinations, hasVisited, i + 1, target - candidates[i], candidates);
hasVisited[i] = false;
tempCombination.remove(tempCombination.size() - 1);
}
}
}

总结：这种类型的题目要比上一题复杂的多，主要在于一个重复元素的问题，

continue;


## 216、1-9 数字的组合求和

Input: k = 3, n = 9

Output:

[[1,2,6], [1,3,5], [2,3,4]]

public List<List<Integer>> combinationSum3(int k, int n) {
List<List<Integer>> combinations = new ArrayList<>();
List<Integer> path = new ArrayList<>();
backtracking(k, n, 1, path, combinations);
return combinations;
}

private void backtracking(int k, int n, int start,
List<Integer> tempCombination, List<List<Integer>> combinations) {

if (k == 0 && n == 0) {
return;
}
if (k == 0 || n == 0) {
return;
}
for (int i = start; i <= 9; i++) {
backtracking(k - 1, n - i, i + 1, tempCombination, combinations);
tempCombination.remove(tempCombination.size() - 1);
}
}

总结：这个题目的特点在于他的输入没有数组，而是简单的两个数字，



## 718、子集

public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> subsets = new ArrayList<>();
List<Integer> tempSubset = new ArrayList<>();
for (int size = 0; size <= nums.length; size++) {
backtracking(0, tempSubset, subsets, size, nums); // 不同的子集大小
}
return subsets;
}

private void backtracking(int start, List<Integer> tempSubset, List<List<Integer>> subsets,
final int size, final int[] nums) {

if (tempSubset.size() == size) {
return;
}
for (int i = start; i < nums.length; i++) {
backtracking(i + 1, tempSubset, subsets, size, nums);
tempSubset.remove(tempSubset.size() - 1);
}
}

总结：在处理子集的问题的时候，需要通过 for (int size = 0; size <= nums.length; size++) {



## 90、含有相同元素求子集

For example,
If nums = [1,2,2], a solution is:

[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]

public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> subsets = new ArrayList<>();
List<Integer> tempSubset = new ArrayList<>();
boolean[] hasVisited = new boolean[nums.length];
for (int size = 0; size <= nums.length; size++) {
backtracking(0, tempSubset, subsets, hasVisited, size, nums); // 不同的子集大小
}
return subsets;
}

private void backtracking(int start, List<Integer> tempSubset, List<List<Integer>> subsets, boolean[] hasVisited,
final int size, final int[] nums) {

if (tempSubset.size() == size) {
return;
}
for (int i = start; i < nums.length; i++) {
if (i != 0 && nums[i] == nums[i - 1] && !hasVisited[i - 1]) {
continue;
}
hasVisited[i] = true;
backtracking(i + 1, tempSubset, subsets, hasVisited, size, nums);
hasVisited[i] = false;
tempSubset.remove(tempSubset.size() - 1);
}
}

与上一题的区别就在于输入数组含有相同元素，



## 131、 分割字符串使得每个部分都是回文数

For example, given s = “aab”,
Return

[
[“aa”,“b”],
[“a”,“a”,“b”]
]

public List<List<String>> partition(String s) {
List<List<String>> partitions = new ArrayList<>();
List<String> tempPartition = new ArrayList<>();
doPartition(s, partitions, tempPartition);
return partitions;
}

private void doPartition(String s, List<List<String>> partitions, List<String> tempPartition) {
if (s.length() == 0) {
return;
}
for (int i = 0; i < s.length(); i++) {
if (isPalindrome(s, 0, i)) {
doPartition(s.substring(i + 1), partitions, tempPartition);
tempPartition.remove(tempPartition.size() - 1);
}
}
}

private boolean isPalindrome(String s, int begin, int end) {
while (begin < end) {
if (s.charAt(begin++) != s.charAt(end--)) {
return false;
}
}
return true;
}

08-20 288

11-28 26
03-25 1万+
09-29 101
06-22 109