回溯模板
private void backTracking(参数) {
if (终止条件) {
保存结果等处理
return;
}
for (int i = start; i <= end; i++) { // 循环
list.add(i); // 增加参数
backTracking(参数);
list.remove(list.size() - 1); // 回溯之后弹出
}
}
1.组合
class Solution {
public List<List<Integer>> combine(int n, int k) {
// 回溯
List<List<Integer>> result = new ArrayList<>();
backTracking(new ArrayList<>(), 1, n, k, result);
return result;
}
private void backTracking(List<Integer> list, int start, int end, int k, List<List<Integer>> result ) {
if (list.size() == k) {
result.add(new ArrayList<>(list));
return;
}
for (int i = start; i <= end; i++) {
list.add(i);
backTracking(list, i+1, end, k, result);
list.remove(list.size() - 1);
}
}
}
2. 组合总和
class Solution {
private List<List<Integer>> resultList = new ArrayList<>();
private int sum = 0;
private LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
backTracking(1,k,n);
return resultList;
}
private void backTracking(int start, int k, int n) {
if (sum > n || path.size() > k) {
return;
}
if (sum ==n && path.size() == k) {
resultList.add(new ArrayList<>(path));
return;
}
for (int i = start; i< 10-(k-path.size()) +1; i++) {
sum += i;
path.add(i);
backTracking(i+1, k, n);
path.removeLast();
sum-=i;
}
}
}
3.电话号组合
class Solution {
private List<String> result = new ArrayList<>();
private StringBuilder stringBuilder = new StringBuilder();
private Map<Character, String[]> keyDigitsMap = new HashMap<>();
{
keyDigitsMap.put('2', new String[]{"a", "b", "c"});
keyDigitsMap.put('3', new String[]{"d", "e", "f"});
keyDigitsMap.put('4', new String[]{"g", "h", "i"});
keyDigitsMap.put('5', new String[]{"j", "k", "l"});
keyDigitsMap.put('6', new String[]{"m", "n", "o"});
keyDigitsMap.put('7', new String[]{"p", "q", "r", "s"});
keyDigitsMap.put('8', new String[]{"t", "u", "v"});
keyDigitsMap.put('9', new String[]{"w", "x", "y", "z"});
}
public List<String> letterCombinations(String digits) {
if (digits == null || digits.length() <=0) {
return result;
}
backTracing(digits, 0);
return result;
}
private void backTracing(String digits, int start) {
if (stringBuilder.length() == digits.length()) {
result.add(stringBuilder.toString());
return;
}
String[] strings = keyDigitsMap.get(digits.charAt(start));
for (int j = 0; j < strings.length; j++) {
stringBuilder.append(strings[j]);
backTracing(digits, start + 1);
stringBuilder.deleteCharAt(stringBuilder.length()-1);
}
}
}
4. 组合之和,字段无限使用
回溯一定是一进一出的
class Solution {
private LinkedList<Integer> list = new LinkedList<>();
private List<List<Integer>> result = new ArrayList<>();
private int sum = 0;
public List<List<Integer>> combinationSum(int[] candidates, int target) {
backTracking(candidates, 0, target);
return result;
}
private void backTracking(int[] candidates, int index, int target) {
if (sum == target) {
result.add(new ArrayList<>(list));
return;
}
if (sum > target) {
return;
}
for (int i = index; i< candidates.length; i++) {
sum += candidates[i];
list.add(candidates[i]);
if (sum < target){
backTracking(candidates, i, target);
}else {
backTracking(candidates, i + 1, target);
}
Integer integer = list.removeLast();
sum -= integer;
}
}
}
5. 组合总和2,结果集不能有重复数组
usesd数组,得好好理解
class Solution {
private List<List<Integer>> result = new ArrayList<>();
private LinkedList<Integer> list = new LinkedList<>();
private int sum = 0;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
boolean[] used = new boolean[candidates.length];
backTracking(candidates, target, 0, used);
return result;
}
private void backTracking(int[] candidates, int target, int start, boolean[] used) {
if (sum == target) {
result.add(new ArrayList<>(list));
return;
}
for (int i = start; i< candidates.length && sum + candidates[i] <= target; i++) {
if ( i >0 && !used[i - 1] && candidates[i-1] == candidates[i]) {
continue;
}
sum += candidates[i];
list.add(candidates[i]);
used[i] = true;
backTracking(candidates, target, i + 1, used);
used[i] = false;
sum -= candidates[i];
list.removeLast();
}
}
}
6. 切割字符串, === 组合
看了半天,真复杂
class Solution {
List<List<String>> result = new ArrayList<>();
LinkedList<String> lists = new LinkedList<>();
public List<List<String>> partition(String s) {
backTracking (s, 0);
return result;
}
private void backTracking(String s, int start) {
if (start == s.length()) {
result.add(new ArrayList<>(lists));
return;
}
for (int i =start; i < s.length(); i++) {
if (!checkPalindrome(s, start, i+1)) {
continue;
}
lists.add(s.substring(start, i + 1));
backTracking(s, i + 1);
lists.removeLast();
}
}
private boolean checkPalindrome(String s, int start, int i) {
i = i -1;
while (start < i) {
if (s.charAt(start) == s.charAt(i)) {
start++;
i --;
}else {
return false;
}
}
return true;
}
}
7. 切割ip
缝缝补补
class Solution {
private List<String> result = new ArrayList<>();
private LinkedList<Integer> list = new LinkedList<>();
public List<String> restoreIpAddresses(String s) {
// 切割,4位数
backTracking(s, 0);
return result;
}
private void backTracking(String s, int start) {
if (list.size() > 4) {
return;
}
if (start >= s.length()) {
if (list.size() == 4) {
result.add(list.stream().map(String::valueOf).collect(Collectors.joining(".")));
}
return;
}
for (int i = start; i< s.length(); i++) {
if (i - start > 3 || s.charAt(start) == '0' && i > start) {
break;
}
if ( 255>=Integer.valueOf(s.substring(start, i+1)) && 0 <= Integer.valueOf(s.substring(start, i+1))) {
list.add(Integer.valueOf(s.substring(start, i+1)));
}else {
continue;
}
backTracking(s, i + 1);
list.removeLast();
}
}
}
8.数组的子数组
class Solution {
private List<List<Integer>> result = new ArrayList<>();
private LinkedList<Integer> list = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) {
backTracking(nums, 0);
return result;
}
private void backTracking(int[] nums, int start) {
result.add(new ArrayList<>(list));
for (int i =start; i< nums.length; i++) {
list.add(nums[i]);
backTracking(nums, i+1);
list.removeLast();
}
}
}
9. 数组的子数组,不能重复,层级去重
class Solution {
private List<List<Integer>> result = new ArrayList<>();
private LinkedList<Integer> list = new LinkedList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
boolean[] used = new boolean[nums.length];
Arrays.sort(nums);
backTracking(nums, 0, used);
return result;
}
private void backTracking(int[] nums, int start, boolean[] used) {
result.add(new ArrayList<>(list));
for (int i =start; i< nums.length; i++) {
if (i > 0 && nums[i] == nums[i-1] && !used[i - 1] ) {
continue;
}
list.add(nums[i]);
used[i] = true;
backTracking(nums, i+1, used);
used[i] = false;
list.removeLast();
}
}
}
10.数组的递增子数组
剪枝!!!,同父节点下不重复
class Solution {
private List<List<Integer>> result = new ArrayList<>();
private LinkedList<Integer> list = new LinkedList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
backTracking(nums, 0);
return result;
}
private void backTracking(int[] nums, int start) {
if (list.size() > 1) {
result.add(new ArrayList<>(list));
}
int [] used = new int[201];
for (int i = start; i < nums.length;i++) {
if (!list.isEmpty() && nums[i] < list.getLast()) {
continue;
}
if (used[nums[i] + 100] == 1) {
continue;
}
list.add(nums[i]);
used[nums[i]+100] = 1;
backTracking(nums, i +1);
list.removeLast();
}
}
}
11. 全排列
每次都从0开始遍历,单树每个元素使用一次。
private List<List<Integer>> result = new ArrayList<>();
private LinkedList<Integer> list = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
boolean[] used = new boolean[nums.length];
backTracking(nums, used);
return result;
}
private void backTracking(int[] nums, boolean[] used) {
if (list.size() == nums.length) {
result.add(new ArrayList<>(list));
return;
}
for (int j = 0; j < nums.length; j++) {
if (used[j]) {
continue;
}
list.add(nums[j]);
used[j] = true;
backTracking(nums, used);
list.removeLast();
used[j] = false;
}
}
12.全排列2,返回不重复的
去重啊,剪枝啊。同层值相同的,并且前一个节点使用过,则剪枝
class Solution {
private List<List<Integer>> result = new ArrayList<>();
private LinkedList<Integer> list = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
boolean[] used = new boolean[nums.length];
Arrays.sort(nums);
backTracking(nums, used);
return result;
}
private void backTracking(int[] nums, boolean[] used) {
if (list.size() == nums.length) {
result.add(new ArrayList<>(list));
}
for (int i = 0; i< nums.length; i++) {
if(used[i]) {
continue;
}
if(i > 0 && !used[i-1] && nums[i] == nums[i-1]) {
continue;
}
list.add(nums[i]);
used[i] = true;
backTracking(nums, used);
list.removeLast();
used[i] = false;
}
}
}
13. n皇后,回溯,手写
class Solution {
private List<List<String>> result = new ArrayList<>();
private LinkedList<Integer> list = new LinkedList<>();
public List<List<String>> solveNQueens(int n) {
backTracking(n);
return result;
}
private void backTracking(int n) {
if (list.size() == n ) {
result.add(getResult(list));
return;
}
for (int i =0 ; i < n; i ++) {
// 竖
if (list.contains(i)) {
continue;
}
// 斜对角
if (!list.isEmpty()) {
int size = list.size();
boolean flag = false;
for (int j = 0; j < list.size(); j++) {
if (size -j == i - list.get(j) ||
size -j == list.get(j) - i) {
flag = true;
break;
}
}
if (flag) {
continue;
}
}
list.add(i);
backTracking(n);
list.removeLast();
}
}
private List<String> getResult(LinkedList<Integer> list) {
int size = list.size();
return list.stream().map(e -> {
StringBuilder sb = new StringBuilder();
int i = 0;
while (i < size) {
if (i == e) {
sb.append("Q");
}else
sb.append(".");
i++;
}
return sb.toString();
}).collect(Collectors.toList());
}
}