回溯法题目总结

1. 数字键盘组合

17. Letter Combinations of a Phone Number

class Solution {
    private static final String[] keys = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    public List<String> letterCombinations(String digits) {
        List<String> ret = new ArrayList<> ();
        String curStr = "";
        if(digits!=null&&digits.length()!=0){
            dfs(digits, -1, 0, ret, curStr);
        }
        return ret;
    }
    // i代表按键数字,j代表按键数字的某一位
    private  void dfs(String digits, int i, int j, List<String> ret, String curStr){

        //获得当前的数字,-1的时候不执行该操作
        if(i>=0){
            int curNum = digits.charAt(i) - '0';
            curStr += keys[curNum].charAt(j);
        }

        // 如果已经检索到最后一位,则不继续往下检索了
        if(i==digits.length()-1){
            ret.add(curStr);
            return;
        }

        //获得当前数字对应的字符串,并将对应位加进当前数组
        int nextNum = digits.charAt(i+1) - '0';
        for(int k=0; k<keys[nextNum].length(); k++){
             System.out.print(k);
            dfs(digits, i+1, k, ret, curStr);
        }   
    }
}

2.在矩阵中寻找字符串

思路:图的深度搜索一般都有套路,如果主程序的n*m个入口;然后递归程序有一个终止返回条件,一个不符合返回条件,然后就是对上下左右的遍历
Leetcode : 79. Word Search (Medium)

class Solution {
    private int[][] direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
    // 用来记录访问过的值,但是每次退出当前节点的子节点时,要恢复
    private boolean[][] visited;
    public boolean exist(char[][] board, String word) {
        if (word == null || word.length() == 0) return true;
        if (board == null || board.length == 0 || board[0].length == 0) return false;
        int n = board.length;
        int m = board[0].length;
        visited = new boolean[n][m];
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                if(board[i][j]==word.charAt(0)){
                    if(dfs(board, word, i, j, 0))  return true;
                }
            }
        }
        return false;
    }

    private boolean dfs(char[][] board, String word, int i, int j, int k){
        if(k==word.length()) {return true;}
        //不符合条件包括四项
        if(i<0||i>=board.length||j<0||j>=board[0].length||board[i][j]!=word.charAt(k)||visited[i][j]){
            return false;
        }
        // if(k==word.length()-1&&board[i][j]==word.charAt(k)) {flag=true; return;}
        // char temp = board[i][j];
        visited[i][j] = true;
        for(int d=0; d<direction.length; d++){
            if (dfs(board, word, i+direction[d][0], j+direction[d][1], k+1)) return true; 
        }   
        visited[i][j] = false;
        return false;    
    }
}

3.字符串排列

Permutations

import java.util.ArrayList;
import java.util.*;
public class Solution {
    public ArrayList<String> Permutation(String str) {
       ArrayList<String> ret= new ArrayList<>();
       if(str.length()==0) return ret;
       else{
           backtracking(str.toCharArray(), 0, ret);
           Collections.sort(ret);
       }
        return ret;
    }
     public void backtracking(char[] str, int i, ArrayList<String> ret){
         if(i==str.length-1) ret.add(String.valueOf(str));
         // 没有不符合条件退回
         else{
             //fix -1 position and 0 exchanges values with other positions 
             // 遍历能交换的元素
             for(int j=i; j<str.length; j++){
                 if(i==j||str[i]!=str[j]){
                     swap(str, i, j);
                     backtracking(str, i+1, ret);
                     swap(str, j, i);
                 }
             }
         }
     }

     public void swap(char[] str, int i, int j){
         char temp = str[i];
         str[i] = str[j];
         str[j] = temp;
     }   

}

4. 组合

Leetcode : 77. Combinations (Medium)
思路:差不多的思路,但是要注意第一层只能是n-k+1, 每往后一层,可选的数字范围就+1,所以每次k都要减1

public List<List<Integer>> combine(int n, int k) {
    List<List<Integer>> ret = new ArrayList<>();
    List<Integer> combineList = new ArrayList<>();
    backtracking(1, n, k, combineList, ret);
    return ret;
}

private void backtracking(int start, int n, int k, List<Integer> combineList, List<List<Integer>> ret){
    if(k == 0){
        ret.add(new ArrayList(combineList)); // 这里要重新构造一个 List
        return;
    }

    for(int i = start; i <= n - k + 1; i++){ // 剪枝

        combineList.add(i);                        // 把 i 标记为已访问
        backtracking(i + 1, n, k - 1, combineList, ret);
        combineList.remove(combineList.size() - 1); // 把 i 标记为未访问
    }
}

5. 数组和为某个数的所有组合

Leetcode : 39. Combination Sum (Medium)

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> ret= new ArrayList<>();
        int sum = 0;
        doCombinationSum(candidates,  ret, target, sum, 0, new ArrayList<>());
        return ret;
    }

    private void doCombinationSum(int[] candidates,  List<List<Integer>> ret, int target, int sum, int start,  List<Integer> list){ 
        if(target<sum) return;
        else if(target==sum) {
            ret.add(new ArrayList<>(list));
            return;
        }
        //因为某个数可以被重复使用多次,所以start在下一层递归中是不需要的
        for(int i=start; i<candidates.length; i++){
            //这个写在递归函数里会保险点,但是不允许
            list.add(candidates[i]);
            doCombinationSum(candidates, ret, target, sum + candidates[i], i, list);
            // 因为返回的时候我们不需要当前记载的元素了。
            list.remove(list.size()-1);

        }
    }
}

6.数组和为某个数的所有组合II

Leetcode : 40. Combination Sum II (Medium)

public List<List<Integer>> combinationSum2(int[] candidates, int target) {
   List<List<Integer>> list = new LinkedList<List<Integer>>();
   // 要先排序
   Arrays.sort(candidates);
   backtrack(list, new ArrayList<Integer>(), candidates, target, 0);
   return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int[] cand, int remain, int start) {

   if(remain < 0) return; /** no solution */
   else if(remain == 0) list.add(new ArrayList<>(tempList));
   else{
      for (int i = start; i < cand.length; i++) {
         //区别在这里 
         if(i > start && cand[i] == cand[i-1]) continue; /** skip duplicates */
         tempList.add(cand[i]);
         backtrack(list, tempList, cand, remain - cand[i], i+1);
         tempList.remove(tempList.size() - 1);
      }
   }
}

7.不含有相同元素的子集

public List<List<Integer>> subsets(int[] nums) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, 0);
    return list;
}

private void backtrack(List<List<Integer>> list , List<Integer> tempList, int [] nums, int start){
    list.add(new ArrayList<>(tempList));
    for(int i = start; i < nums.length; i++){
        tempList.add(nums[i]);
        backtrack(list, tempList, nums, i + 1);
        tempList.remove(tempList.size() - 1);
    }
}

8. 含有相同元素的子集

public List<List<Integer>> subsetsWithDup(int[] nums) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, 0);
    return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int start){
    list.add(new ArrayList<>(tempList));
    for(int i = start; i < nums.length; i++){
        //只能选一个
        if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates
        tempList.add(nums[i]);
        backtrack(list, tempList, nums, i + 1);
        tempList.remove(tempList.size() - 1);
    }
} 

9. 数组的所有排列组合结果

public List<List<Integer>> permute(int[] nums) {
   List<List<Integer>> list = new ArrayList<>();
   // Arrays.sort(nums); // not necessary
   backtrack(list, new ArrayList<>(), nums);
   return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums){
   if(tempList.size() == nums.length){
      list.add(new ArrayList<>(tempList));
   } else{
      for(int i = 0; i < nums.length; i++){ 
         if(tempList.contains(nums[i])) continue; // element already exists, skip
         tempList.add(nums[i]);
         backtrack(list, tempList, nums);
         tempList.remove(tempList.size() - 1);
      }
   }
} 

10.数组的所有排列组合结果II

public List<List<Integer>> permuteUnique(int[] nums) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, new boolean[nums.length]);
    return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, boolean [] used){
    if(tempList.size() == nums.length){
        list.add(new ArrayList<>(tempList));
    } else{
        for(int i = 0; i < nums.length; i++){
            if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i - 1]) continue;
            used[i] = true; 
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, used);
            used[i] = false; 
            tempList.remove(tempList.size() - 1);
        }
    }
}

11.分割字符串成回文字符串

public List<List<String>> partition(String s) {
   List<List<String>> list = new ArrayList<>();
   backtrack(list, new ArrayList<>(), s, 0);
   return list;
}

public void backtrack(List<List<String>> list, List<String> tempList, String s, int start){
   if(start == s.length())
      list.add(new ArrayList<>(tempList));
   else{
      for(int i = start; i < s.length(); i++){
         if(isPalindrome(s, start, i)){
            tempList.add(s.substring(start, i + 1));
            backtrack(list, tempList, s, i + 1);
            tempList.remove(tempList.size() - 1);
         }
      }
   }
}

public boolean isPalindrome(String s, int low, int high){
   while(low < high)
      if(s.charAt(low++) != s.charAt(high--)) return false;
   return true;
} 
    原文作者:回溯法
    原文地址: https://blog.csdn.net/u010814042/article/details/79576176
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞