《剑指offer》 -day14- 搜索与回溯算法(中等)【DFS】

剑指 Offer 12. 矩阵中的路径


在这里插入图片描述

DFS

思路 🤔

  1. 遍历矩阵中所有元素:若矩阵中当前元素 board[i][j]word.charAt(0) 相等时,尝试使用 dfs 进行判断
  2. 由于是只有找到一个符合条件的,即可。满足条件时,则可以直接返回,所以可以将 dfs 设置为带有返回值 boolean dfs(StringBuilder cnt, int x, int y, int index)
  3. 每次 dfs 判断当前位置 (x, y) 上、下、左、右 四个方法对应的新位置 (xx, yy)
    • 若新位置越界(预防污染的写法)、新位置已经访问过、新位置元素和 word.charAt(index + 1)不相等,则跳过;
    • 否则,则使用新位置 (xx, yy) 继续进行 dfs
class Solution {
    int m;
    int n;
    String word;
    char[][] board;
    boolean[][] visited;
    int[] dirx = {-1, 1, 0, 0};
    int[] diry = {0, 0, -1, 1};

    public boolean exist(char[][] board, String word) {
        this.word = word;
        this.board = board;
        this.m = board.length;
        this.n = board[0].length;
        this.visited = new boolean[m][n];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 矩阵中当前元素和word开头元素相等时,尝试使用dfs判断
                if (board[i][j] == word.charAt(0)) {
                    visited[i][j] = true;
                    if (dfs(new StringBuilder(word.charAt(0)).append(word.charAt(0)), i, j, 1)) {
                        return true;
                    }
                    visited[i][j] = false; // 回溯
                }
            }
        }
        return false;
    }

    boolean dfs(StringBuilder cnt, int x, int y, int index) {
        if (cnt.toString().equals(word)) {
            return true;
        }
        // 剪枝
        if (index > word.length()) {
            return false;
        }
        for (int i = 0; i < 4; i++) {
            int xx = x + dirx[i];
            int yy = y + diry[i];
            // 新位置越界(预防污染的写法)
            if (xx < 0 || xx >= m || yy < 0 || yy >= n) {
                continue;
            }
            // 新位置已经访问过
            if (visited[xx][yy]) {
                continue;
            }
            // 新位置元素和word[index + 1]不相等
            if ((index + 1) < word.length() && board[xx][yy] != word.charAt(index)) {
                continue;
            }
            visited[xx][yy] = true;
            cnt.append(board[xx][yy]);
            if (dfs(cnt, xx, yy, index + 1)) {
                return true;
            }
            cnt.deleteCharAt(cnt.length() - 1); // 回溯
            visited[xx][yy] = false;
        }
        return cnt.equals(word);
    }

    public static void main(String[] args) {
        char[][] board = {{'A','B','C','E'},{'S','F','C','S'},{'A','D','E','E'}};
        String word = "ABCCED";
        System.out.println(new Solution().exist(board, word));

        StringBuilder sb = new StringBuilder("ABCCED");
        System.out.println(sb.equals(word));
        System.out.println(word.equals(sb));
    }
}

在这里插入图片描述

剑指 Offer 13. 机器人的运动范围

在这里插入图片描述
提示:

  • 1 < = n , m < = 100 1 <= n,m <= 100 1<=n,m<=100
  • 0 < = k < = 20 0 <= k <= 20 0<=k<=20

DFS

思路 🤔

  1. res 为最终所求结果,并初始化 int res = 1; (因为 k > = 0 k>=0 k>=0 ( 0 , 0 ) (0, 0) (0,0) 一定符合题意);
  2. 每次 dfs 判断当前位置 (x, y) 上、下、左、右 四个方法对应的新位置 (xx, yy)
    • 若新位置越界(预防污染的写法)、新位置已经访问过、新位置元素已经不在满足题意,则跳过;
    • 否则,则说明找到了下一个符合题意的位置,则 res++;,并使用新位置 (xx, yy) 继续进行 dfs
class Solution {
    int m;
    int n;
    int k;
    int res = 1; // 第一个元素访问过,即 k>=0时 (0, 0) 一定符合题意。
    boolean[][] visited;
    int[] dirx = {-1, 1, 0, 0};
    int[] diry = {0, 0, -1, 1};

    public int movingCount(int m, int n, int k) {
        if (k < 0) return 0;
        this.k = k;
        this.m = m;
        this.n = n;
        this.visited = new boolean[m][n];
        // 第一个元素访问过
        visited[0][0] = true;
        dfs(0, 0);
        return res;
    }

    void dfs(int x, int y) {
        for (int i = 0; i < 4; i++) {
            int xx = x + dirx[i];
            int yy = y + diry[i];
            // 新位置越界(预防污染的写法)
            if (xx < 0 || xx >= m || yy < 0 || yy >= n) {
                continue;
            }
            // 新位置已经访问过
            if (visited[xx][yy]) {
                continue;
            }
            // 新位置不满足题意
            if (getSum(xx) + getSum(yy) > k) {
                continue;
            }
            res++;
            visited[xx][yy] = true;
            dfs(xx, yy);
            // visited[xx][yy] = false; // 这里不回溯
        }
    }

    int getSum(int num) {
        int sum = 0;
        while (num > 0) {
            sum += (num % 10);
            num /= 10;
        }
        return sum;
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值