Skip to content

回溯


46. 全排列

java
// 全排列的长度固定,需要flag标记
class Solution {
    private List<List<Integer>> ans = new ArrayList<>();

    public List<List<Integer>> permute(int[] nums) {
        boolean[] flag = new boolean[nums.length];
        traceBack(nums, 0, flag, new ArrayList<>(nums.length));

        return ans;
    }

    public void traceBack(int[] nums, int depth, boolean[] flag, List<Integer> temp) {
        if (depth == nums.length) {
            ans.add(new ArrayList<>(temp));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (flag[i]) continue;
            flag[i] = true;
            temp.add(nums[i]);
            traceBack(nums, depth + 1, flag, temp);
            flag[i] = false;
            temp.remove(temp.size() - 1);
        }
    }
}

78. 子集

java
// 子集遍历了所有的路径,感觉这题还是很重要的
// 输入:nums = [1,2,3]
// 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
class Solution {
    private List<List<Integer>> ans = new ArrayList<>();

    public List<List<Integer>> subsets(int[] nums) {
        traceBack(nums, 0, new ArrayList<Integer>());
        return ans;
    }

    public void traceBack(int[] nums, int start, List<Integer> path) {
        ans.add(new ArrayList(path));
        for (int i = start; i < nums.length; i++) {
            path.add(nums[i]);
            traceBack(nums, i + 1, path);
            path.remove(path.size() - 1);
        }
    }
}

17. 电话号码的字母组合

java
class Solution {
    private List<String> ans = new ArrayList<>();
    private String[] button = new String[] { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };

    public List<String> letterCombinations(String digits) {
        if (digits.length() != 0) {
            dfs(digits, 0, new char[digits.length()]);
        }
        return ans;
    }

    public void dfs(String digits, int depth, char[] letter) {
        if (depth == digits.length()) {
            ans.add(new String(letter));
            return;
        }
        int num = digits.charAt(depth) - '0';
        String curstr = button[num];
        for (int i = 0; i < curstr.length(); i++) {
            letter[depth] = curstr.charAt(i);
            dfs(digits, depth + 1, letter);
        }
    }
}

39. 组合总和

java
// 看题目条件都是比较小的正数,超出范围即可return
// 本题允许重复,下一层的start从i开始
class Solution {
    private List<List<Integer>> ans = new ArrayList<>();

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

    public void traceBack(int[] candidates, int target, int start, int curSum, List<Integer> path) {
        if (curSum == target) {
            ans.add(new ArrayList<Integer>(path));
            return;
        } else if (curSum > target) {
            return;
        }
        for (int i = start; i < candidates.length; i++) {
            // curSum += candidates[i]; 这里可以简化,往下传递的加上即可
            path.add(candidates[i]);
            traceBack(candidates, target, i, curSum + candidates[i], path);
            // curSum -= candidates[i];
            path.remove(path.size() - 1);
        }
    }
}

22. 括号生成

java
// 使用字符数组即可,简单的回溯,当前层l + r直接覆盖下标元素即可
class Solution {
    List<String> ans = new ArrayList<>();

    public List<String> generateParenthesis(int n) {
        dfs(n, 0, 0, new char[n * 2]);
        return ans;
    }

    public void dfs(int n, int l, int r, char[] temp) {
        if (l < r || l > n) {
            return;
        }
        if (l + r == n * 2) {
            ans.add(new String(temp));
            return;
        }
        temp[l + r] = '(';
        dfs(n, l + 1, r, temp);
        temp[l + r] = ')';
        dfs(n, l, r + 1, temp);
    }
}

79. 单词搜索

java
// 回溯即可,需要深度,最好有返回值剪枝终止
// 考虑仅包含英文字母,为了省去flag的空间,直接在原数组中用空格标记,word字符串还原
class Solution {
    public boolean exist(char[][] board, String word) {
        for (int x = 0; x < board.length; x++) {
            for (int y = 0; y < board[0].length; y++) {
                if (dfs(board, word, x, y, 0)) {
                    return true;
                }
            }
        }
        return false;
    }

    public boolean dfs(char[][] board, String word, int x, int y, int depth) {
        if (depth == word.length()) {
            return true;
        }
        if (x < 0 || x >= board.length || y < 0 || y >= board[0].length) {
            return false;
        }
        // 题目给定条件是大小写英文字符,经过的点设为空格合理
        if (board[x][y] != word.charAt(depth)) {
            return false;
        }
        // 匹配才能进入下层递归,还原可以用word对应位置字符
        board[x][y] = ' ';
        boolean res = dfs(board, word, x - 1, y, depth + 1) ||
                dfs(board, word, x + 1, y, depth + 1) ||
                dfs(board, word, x, y - 1, depth + 1) ||
                dfs(board, word, x, y + 1, depth + 1);
        board[x][y] = word.charAt(depth);
        return res;
    }
}

131. 分割回文串

java
// 注意题目条件是,每个子串都是回文子串,将判断是否是回文抽离出来
class Solution {
    private List<List<String>> ans = new ArrayList<>();

    public List<List<String>> partition(String s) {
        dfs(s, 0, new ArrayList<String>());
        return ans;
    }

    public void dfs(String s, int start, List<String> path) {
        if (start == s.length()) {
            ans.add(new ArrayList<>(path));
            return;
        }
        for (int end = start; end < s.length(); end++) {
            // s[start, end]不是回文, continue
            if (!isABA(s, start, end)) {
                continue;
            }
            path.add(s.substring(start, end + 1));
            dfs(s, end + 1, path);
            path.remove(path.size() - 1);
        }
    }

    public boolean isABA(String s, int start, int end) {
        while (start < end) {
            if (s.charAt(start++) != s.charAt(end--)) {
                return false;
            }
        }
        return true;
    }
}

51. N 皇后

java
class Solution {
    List<List<String>> ans;
    int[][] matrix;
    
    public void killPath(int x, int y, int add, int n){
        matrix[x][y] -= add;
        for(int i = 0; i < n; i++){
            matrix[i][y] += add;
            matrix[x][i] += add;
        }
        for(int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--){
            matrix[i][j] += add;
        }
        for(int i = x + 1, j = y + 1; i < n && j < n; i++, j++){
            matrix[i][j] += add;
        }
        for(int i = x - 1, j = y + 1; i >= 0 && j < n; i--, j++){
            matrix[i][j] += add;
        }
        for(int i = x + 1, j = y - 1; i < n && j >= 0; i++, j--){
            matrix[i][j] += add;
        }
    }

    public void traceBack(int depth, int n){
        if(depth == n){
            //记录结果
            List<String> res = new ArrayList<>(n);
            for(int i = 0; i < n; i++){
                char[] s = new char[n];
                for(int j = 0; j < n; j++){
                    s[j] = matrix[i][j] == 1 ? 'Q' : '.';
                }
                res.add(new String(s));
            }
            ans.add(res);
            return;
        }
        for(int i = 0; i < n; i++){
            if(matrix[depth][i] > 0) continue;
            //四个方向进行标记
            killPath(depth, i, 1, n);
            traceBack(depth+1, n);
            //四个方向标记解除
            killPath(depth, i, -1, n);
        }
    }
    
    public List<List<String>> solveNQueens(int n) {
        ans = new ArrayList();
        matrix = new int[n][n];

        traceBack(0, n);
        return ans;
    }
}