力扣技巧-回溯

这篇博客详细解析了如何使用回溯算法解决LeetCode上的多个经典问题,包括N皇后、全排列、解数独、括号生成等,并提供了题解,最后总结了在哪些情况下不需要使用回溯算法。
51. N 皇后

题解:

class Solution {
    private int n;
    private boolean[] col;
    private boolean[] master;
    private boolean[] slave;
    private List<List<String>> res;
    public List<List<String>> solveNQueens(int n) {
        this.n = n;
        col = new boolean[n];
        master = new boolean[2 * n - 1];
        slave = new boolean[2 * n - 1];
        res = new ArrayList<>();
        Deque<Integer> stack = new ArrayDeque<>();
        dfs(0, stack);
        return res;
    }
    private void dfs(int row, Deque<Integer> stack) {
        if (row == n) {
            List<String> board = covert2Board(stack, n);
            res.add(board);
            return;
        }
        for (int i = 0; i < n; i ++) {
            if (!col[i] && !master[row + i] && !slave[row - i + n - 1]) {
                stack.addLast(i);
                col[i] = true;
                master[row + i] = true;
                slave[row - i + n - 1] = true;
                dfs(row + 1, stack);
                col[i] = false;
                master[row + i] = false;
                slave[row - i + n - 1] = false;
                stack.removeLast();
            }
        }
    }
    // 保存一个结果的stack,皇后数量:n
    private List<String> covert2Board(Deque<Integer> stack, int n) {
        List<String> board = new ArrayList<>();
        for (Integer num : stack) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < n; i ++) {
                sb.append(".");
            }
            sb.replace(num, num + 1, "Q");
            board.add(sb.toString());
        }
        return board;
    }
}
46. 全排列

题解:

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        Deque<Integer> path = new ArrayDeque<>();
        List<List<Integer>> res = new ArrayList<>();
        boolean[] visited = new boolean[nums.length];
        dfs(nums, -1, visited, path, res);
        return res;
    }

    private void dfs(int[] nums, int index, boolean[] visited, Deque<Integer> path, List<List<Integer>> res) {
        final int n = nums.length;
        if (path.size() == n) {
            res.add(new ArrayList<>(path));
            return;
        }

        for (int i = 0; i < n; i ++) {
            if (visited[i]) {
                continue;
            }
            path.addLast(nums[i]);
            visited[i] = true;
            dfs(nums, i, visited, path, res);
            visited[i] = false;
            path.removeLast();
        }
    }
}
47. 全排列 II

题解:

class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        Deque<Integer> path = new ArrayDeque<>();
        List<List<Integer>> res = new ArrayList<>();
        boolean[] visited = new boolean[nums.length];
        Arrays.sort(nums);
        dfs(nums, 0, path, visited, res);
        return res;
    }

    private void dfs(int[] nums, int len, Deque<Integer> path, boolean[] visited, List<List<Integer>> res) {

        final int n = nums.length;
        if (len == n) {
            res.add(new ArrayList<>(path));
            return;
        }

        for (int i = 0; i < n; i ++) {
            if (visited[i]) {
                continue;
            }
            if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) {
                continue;
            }
            path.addLast(nums[i]);
            visited[i] = true;
            dfs(nums, len + 1, path, visited, res);
            visited[i] = false;
            path.removeLast();
        }

    }
}
37. 解数独

题解:

class Solution {

    private int m;
    private int n;
    private boolean[][] rows;
    private boolean[][] cols;
    private boolean[][] blocks;

    public void solveSudoku(char[][] board) {
        this.m = board.length;
        this.n = board[0].length;
        rows = new boolean[9][10];
        cols = new boolean[9][10];
        blocks = new boolean[9][10];
        for (int i = 0; i < m; i ++) {
            for (int j = 0; j < n; j ++) {
                if ('.' != board[i][j]) {
                    char number = board[i][j];
                    rows[i][number - '0'] = true;
                    cols[j][number - '0'] = true;
                    blocks[blockIndex(i, j)][number - '0'] = true;
                }
            }
        }
        dfs(board, 0);
    }

    private boolean dfs(char[][] board, int depth) {

        if (depth == 81) {
            return true;
        }

        int row = rowIndex(depth);
        int col = colIndex(depth);

        if ('.' != board[row][col]) {
            return dfs(board, depth + 1);
        }

        for (int i = 1; i < 10; i ++) {
            if (rows[row][i] || cols[col][i] || blocks[blockIndex(row, col)][i]) {
                continue;
            }
            board[row][col] = (char)(i + '0');
            rows[row][i] = true;
            cols[col][i] = true;
            blocks[blockIndex(row, col)][i] = true;
            if (dfs(board, depth + 1)) {
                return true;
            }
            rows[row][i] = false;
            cols[col][i] = false;
            blocks[blockIndex(row, col)][i] = false;
            board[row][col] = '.';
        }

        return false;
    }

    private int rowIndex(int depth) {
        return depth / 9;
    }

    private int colIndex(int depth) {
        return depth % 9;
    }

    private int blockIndex(int i, int j) {
        return i / 3 * 3 + j / 3;
    }
}
22. 括号生成

题解:

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> res = new ArrayList<>();
        dfs("", res, 0, 0, n);
        return res;
    }

    private void dfs(String s, List<String> res, int num, int index, int n) {

        if (num > n || index > 2 * n) {
            return;
        }

        if (index == 2 * n && num == n) {
            if (checkParenthesis(s)) {
                res.add(s);
            }
            return;
        }

        dfs(s + "(", res, num + 1, index + 1, n);
        dfs(s + ")", res, num, index + 1, n);
    }

    private boolean checkParenthesis(String s) {

        final int n = s.length();
        if (0 != (n % 2)) {
            return false;
        }

        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < n; i ++) {
            char c = s.charAt(i);
            if ('(' == c) {
                stack.push(c);
            } else {
                if (stack.isEmpty()) {
                    return false;
                }
                stack.pop();
            }
        }

        return stack.isEmpty();
    }
}
17. 电话号码的字母组合

题解:

class Solution {

    private String[] strs = new String[]{
        "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"
    };

    public List<String> letterCombinations(String digits) {
        List<String> res = new ArrayList<>();
        if (null == digits || "".equals(digits)) {
            return res;
        }
        dfs("", 0, digits, res);
        return res;
    }

    private void dfs(String s, int depth, String digits, List<String> res) {

        final int n = digits.length();
        if (depth == n) {
            res.add(s);
            return;
        }
        
        String str = strs[digits.charAt(depth) - '0'];
        for (int i = 0; i < str.length(); i ++) {
            char c = str.charAt(i);
            dfs(s + c, depth + 1, digits, res);
        }
    }
}
39. 组合总和

题解:

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        Deque<Integer> path = new LinkedList<>();
        dfs(candidates, target, 0, 0, path, res);
        return res;
    }

    private void dfs(int[] candidates, int target, int index, int sum, Deque<Integer> path, List<List<Integer>> res) {
        final int n = candidates.length;

        if (sum == target) {
            res.add(new ArrayList<>(path));
            return;
        }

        if (sum > target) {
            return;
        }

        for (int i = index; i < n; i ++) {
            path.addLast(candidates[i]);
            dfs(candidates, target, i, sum + candidates[i], path, res);
            path.removeLast();
        }
    }
}
40. 组合总和 II

题解:

class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        Deque<Integer> path = new ArrayDeque<>();
        boolean[] visited = new boolean[candidates.length];
        Arrays.sort(candidates);
        dfs(candidates, 0, visited, -1, target, path, res);
        return res;
    }

    private void dfs(int[] candidates, int sum, boolean[] visited, int index, int target, Deque<Integer> path, List<List<Integer>> res) {

        if (sum == target) {
            res.add(new ArrayList<>(path));
            return;
        }

        if (sum > target) {
            return;
        }

        for (int i = index + 1; i < candidates.length; i ++) {

            if (i > 0 && candidates[i] == candidates[i - 1] && !visited[i - 1]) {
                continue;
            }

            path.addLast(candidates[i]);
            visited[i] = true;
            dfs(candidates, sum + candidates[i], visited, i, target, path, res);
            visited[i] = false;
            path.removeLast();
        }
    }
}
216. 组合总和 III

题解:

class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {
        Deque<Integer> path = new ArrayDeque<>();
        List<List<Integer>> res = new ArrayList<>();
        dfs(0, 0, 0, k, n, path, res);
        return res;
    }

    private void dfs(int index, int num, int sum, int k, int n, Deque<Integer> path, List<List<Integer>> res) {

        if (num == k && sum == n) {
            res.add(new ArrayList<>(path));
            return;
        }

        if (num > k || sum > n) {
            return;
        }

        for (int i = index + 1; i < 10; i ++) {
            path.addLast(i);
            dfs(i, num + 1, sum + i, k, n, path, res);
            path.removeLast();
        }
    }
}
78. 子集

题解:

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        Deque<Integer> path = new ArrayDeque<>();
        List<List<Integer>> res = new ArrayList<>();
        dfs(nums, -1, path, res);
        return res;
    }

    private void dfs(int[] nums, int index, Deque<Integer> path, List<List<Integer>> res) {

        res.add(new ArrayList<>(path));

        for (int i = index + 1; i < nums.length; i ++) {
            path.addLast(nums[i]);
            dfs(nums, i, path, res);
            path.removeLast();
        }
    }
 }
90. 子集 II

题解:

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Deque<Integer> path = new ArrayDeque<>();
        Arrays.sort(nums);
        boolean[] visited = new boolean[nums.length];
        dfs(nums, -1, visited, path, res);
        return res;
    }

    private void dfs(int[] nums, int index, boolean[] visited, Deque<Integer> path, List<List<Integer>> res) {

        res.add(new ArrayList<>(path));

        for (int i = index + 1; i < nums.length; i ++) {
            
            if (visited[i]) {
                continue;
            }

            if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) {
                continue;
            }

            visited[i] = true;
            path.addLast(nums[i]);
            dfs(nums, i, visited, path, res);
            path.removeLast();
            visited[i] = false;
        }
    }
}
1593. 拆分字符串使唯一子字符串的数目最大

题解:

class Solution {

    private int res = 1;

    public int maxUniqueSplit(String s) {
        Set<String> visited = new HashSet<>();
        dfs(s, 0, visited);
        return res;
    }

    private void dfs(String s, int sum, Set<String> visited) {

        final int n = s.length();

        if (0 == n) {
            res = Math.max(res, sum);
            return;
        }

        for (int i = 1; i <= n; i ++) {
            String preStr = s.substring(0, i);
            String postStr = s.substring(i, n);
            if (visited.contains(preStr)) {
                continue;
            }
            visited.add(preStr);
            dfs(postStr, sum + 1, visited);
            visited.remove(preStr);
        }
    }


}
79. 单词搜索

题解:

class Solution {

    private int[][] directions = new int[][]{
        {-1, 0}, {0, 1}, {1, 0}, {0, -1}
    };
    private int m;
    private int n;

    public boolean exist(char[][] board, String word) {
        m = board.length;
        n = board[0].length;
        boolean[][] visited = new boolean[m][n];
        for (int i = 0; i < m; i ++) {
            for (int j = 0; j < n; j ++) {
                visited[i][j] = true;
                if (dfs(board, i, j, visited, word, 0)) {
                    return true;
                }
                visited[i][j] = false;    
            }
        }
        return false;
    }

    private boolean dfs(char[][] board, int row, int col, boolean[][] visited, String word, int index) {
        
        if (board[row][col] != word.charAt(index)) {
            return false;
        }

        final int len = word.length();
        if (index == len - 1) {
            return true;
        }


        for (int d = 0; d < directions.length; d ++) {
            int x = row + directions[d][0];
            int y = col + directions[d][1];
            if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y]) {
                continue;
            }
            visited[x][y] = true;
            if (dfs(board, x, y, visited, word, index + 1)) {
                return true;
            }
            visited[x][y] = false;
        }

        return false;
    }
}
695. 岛屿的最大面积

题解:

class Solution {

    private int m;
    private int n;
    private int[][] directions = new int[][]{
        {-1, 0}, {1, 0}, {0, 1}, {0, -1}
    };
    private int res;
    private Integer sum;

    public int maxAreaOfIsland(int[][] grid) {
        m = grid.length;
        n = grid[0].length;
        boolean[][] visited = new boolean[m][n];
        res = 0;
        for (int i = 0; i < m; i ++) {
            for (int j = 0; j < n; j ++) {
                if (1 == grid[i][j]) {
                    sum = 1;
                    visited[i][j] = true;
                    dfs(grid, i, j, visited);
                    visited[i][j] = false;
                }
            }
        }

        return res;
    }

    private void dfs(int[][] grid, int row, int col, boolean[][] visited) {
        res = Math.max(res, sum);

        grid[row][col] = 0;

        for (int d = 0; d < directions.length; d ++) {
            int x = row + directions[d][0];
            int y = col + directions[d][1];
            if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y] || 0 == grid[x][y]) {
                continue;
            }
            visited[x][y] = true;
            sum ++;
            dfs(grid, x, y, visited);
            visited[x][y] = false;
        }
    }


}
417. 太平洋大西洋水流问题

题解:

class Solution {

    private int m;
    private int n;
    private int[][] directions = new int[][]{
        {-1, 0}, {1, 0}, {0, -1}, {0, 1}
    };

    public List<List<Integer>> pacificAtlantic(int[][] heights) {
        m = heights.length;
        n = heights[0].length;
        List<List<Integer>> res = new ArrayList<>();
        for (int i = 0; i < m; i ++) {
            for (int j = 0; j < n; j ++) {
                boolean[][] visited = new boolean[m][n];
                visited[i][j] = true;
                if (pacificDfs(heights, i, j, visited) && atlanticDfs(heights, i, j, visited)) {
                    List<Integer> list = new ArrayList<>();
                    list.add(i);
                    list.add(j);
                    res.add(list);
                }
                visited[i][j] = false;
            }
        }

        return res;
    }

    private boolean pacificDfs(int[][] heights, int row, int col, boolean[][] visited) {

        for (int d = 0; d < directions.length; d ++) {
            int x = row + directions[d][0];
            int y = col + directions[d][1];
            if (x < 0 || y < 0) {
                return true;
            }
            if (x >= m || y >= n || visited[x][y] || heights[x][y] > heights[row][col]) {
                continue;
            }
            visited[x][y] = true;
            boolean flag = pacificDfs(heights, x, y, visited);
            visited[x][y] = false;
            if (flag) {
                return true;
            }
        }

        return false;
    }

    private boolean atlanticDfs(int[][] heights, int row, int col, boolean[][] visited) {

        for (int d = 0; d < directions.length; d ++) {
            int x = row + directions[d][0];
            int y = col + directions[d][1];
            if (x >= m || y >= n) {
                return true;
            }
            if (x < 0 || y < 0 || visited[x][y] || heights[x][y] > heights[row][col]) {
                continue;
            }
            visited[x][y] = true;
            boolean flag = atlanticDfs(heights, x, y, visited);
            visited[x][y] = false;
            if (flag) {
                return true;
            }
        }

        return false;
    }


}
1020. 飞地的数量

题解:

class Solution {

    private int m;
    private int n;
    private int[][] directions = new int[][]{
        {-1, 0}, {1, 0}, {0, -1}, {0, 1} 
    };

    public int numEnclaves(int[][] grid) {
        m = grid.length;
        n = grid[0].length;
        boolean[][] visited = new boolean[m][n];
        for (int i = 0; i < m; i ++) {
            for (int j = 0; j < n; j ++) {
                if ((0 == i || (m - 1 == i) || 0 == j || (n - 1 == j)) && (1 == grid[i][j])) {
                    dfs(grid, i, j, visited);
                }
            }
        }

        int sum = 0;
        for (int i = 0; i < m; i ++) {
            for (int j = 0; j < n; j ++) {
                if (1 == grid[i][j]) {
                    sum ++;
                }
            }
        }

        return sum;
    }

    private void dfs(int[][] grid, int row, int col, boolean[][] visited) {

        grid[row][col] = 0;

        for (int d = 0; d < directions.length; d ++) {
            int x = row + directions[d][0];
            int y = col + directions[d][1];
            if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y] || 0 == grid[x][y]) {
                continue;
            } 
            visited[x][y] = true;
            dfs(grid, x, y, visited);
            visited[x][y] = false;
        }
    }
}
1254. 统计封闭岛屿的数目

题解:

class Solution {

    private int m;
    private int n;
    private int[][] directions = new int[][]{
        {-1, 0}, {0, -1}, {1, 0}, {0, 1}
    };

    public int closedIsland(int[][] grid) {
        m = grid.length;
        n = grid[0].length;
        boolean[][] visited = new boolean[m][n];
        for (int i = 0; i < m; i ++) {
            for (int j = 0; j < n; j ++) {
                if ((0 == i || (m - 1 == i) || 0 == j || (n - 1 == j)) && 0 == grid[i][j]) {
                    visited[i][j] = true;
                    dfs(grid, i, j, visited);
                    visited[i][j] = false;
                }
            }
        }

        int res = 0;
        for (int i = 0; i < m; i ++) {
            for (int j = 0; j < n; j ++) {
                if (0 == grid[i][j]) {
                    res ++;
                    visited[i][j] = true;
                    dfs(grid, i, j, visited);
                    visited[i][j] = false;
                }
            }
        }

        return res;
    }

    private void dfs(int[][] grid, int row, int col, boolean[][] visited) {

        grid[row][col] = 1;

        for (int d = 0; d < directions.length; d ++) {
            int x = row + directions[d][0];
            int y = col + directions[d][1];
            if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y] || 1 == grid[x][y]) {
                continue;
            }
            visited[x][y] = true;
            dfs(grid, x, y, visited);
            visited[x][y] = false;
        }
    }
}
面试题13. 机器人的运动范围

总结:不需要回溯
题解:

class Solution {

    private int[][] directions = new int[][]{
        {-1, 0}, {1, 0}, {0, -1}, {0, 1}
    };
    private int res = 0;

    public int movingCount(int m, int n, int k) {
        boolean[][] visited = new boolean[m][n];
        visited[0][0] = true;
        dfs(0, 0, m, n, k, visited);
        return res;
    }

    private void dfs(int row, int col, int m, int n, int k, boolean[][] visited) {

        if (checkNumber(row) + checkNumber(col) > k) {
            return;
        }

        res ++;

        for (int d = 0; d < directions.length; d ++) {
            int x = row + directions[d][0];
            int y = col + directions[d][1];
            if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y]) {
                continue;
            }
            visited[x][y] = true;
            dfs(x, y, m, n, k, visited);
        }
    }

    private int checkNumber(int number) {
        int sum = 0;
        while (number > 0) {
            sum += (number % 10);
            number = number / 10;
        }
        return sum;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值