15-lt-机器人的运动范围

一、题目

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

二、解法思路

 2.1 看到题目想到的思路

看到题目首选想到的是 机器人只能 往右和下方向移动,并且不能超出临界和数位之和;依次编码,发现在大的矩阵中,发现有些数位之和的位置能满足 但是走不通,因此找到了 base case 联通性,也就是机器人能否到达下一个条件满足区域。

参考:解题思路

下面看下别人的图:图片来源 图片地址

 三角形区域都是满足条件的位置,但是我们从(0,0)处出发,会发现我们不能够走到下一个连通区域。

 

 能够发现在(9,0)和(0,9)的位置,我们能够将一些不可达的解转变为可达解;因此对于(9,0)和(0,9)的位置我们需要单独处理;

(9,10)和(10,9)也能够将不可达解转换为可达解,也需要进行注意;

 

根据可达解的结构和连通性,易推出机器人可 仅通过向右和向下移动,访问所有可达解 。

三角形内部: 全部连通,易证;
两三角形连通处: 若某三角形内的解为可达解,则必与其左边或上边的三角形连通(即相交),即机器人必可从左边或上边走进此三角形。

 

实际上这边还有一个知识点会经常使用到:数位之和

int sums(int x){
    int s = 0;
    while(x != 0) {
        s += x % 10;
        x = x / 10;
    }
    return s;
}


2.2 思路和题解是否有一致 ,是否有更好的解法

不一致,选择使用BFS或者DFS进行求解

解题方法

BFS: 使用队列进行遍历

广度优先遍历 BFS
BFS/DFS : 两者目标都是遍历整个矩阵,不同点在于搜索顺序不同。DFS 是朝一个方向走到底,再回退,以此类推;BFS 则是按照“平推”的方式向前搜索。
BFS 实现: 通常利用队列实现广度优先遍历。
算法解析:
初始化: 将机器人初始点 (0, 0)(0,0) 加入队列 queue ;
迭代终止条件: queue 为空。代表已遍历完所有可达解。
迭代工作:
单元格出队: 将队首单元格的 索引、数位和 弹出,作为当前搜索单元格。
判断是否跳过: 若 ① 行列索引越界 或 ② 数位和超出目标值 k 或 ③ 当前元素已访问过 时,执行 continue 。
标记当前单元格 :将单元格索引 (i, j) 存入 Set visited 中,代表此单元格 已被访问过 。
单元格入队: 将当前元素的 下方、右方 单元格的 索引、数位和 加入 queue 。
返回值: Set visited 的长度 len(visited) ,即可达解的位置。

class Solution {
    public int movingCount(int m, int n, int k) {
        boolean[][] visited = new boolean[m][n];
        int res = 0;
        //创建队列
        Queue<int[]> queue = new LinkedList<int[]>();

        queue.add(new int[]{0, 0, 0, 0});

        while (queue.size() > 0) {
            //第一个节点
            int[] x = queue.poll();
            int i = x[0], j = x[1], si = x[2], sj = x[3];
            if (i >= m || j >= n || k < si + sj || visited[i][j]) continue;
            visited[i][j] = true;
            res++;
            queue.add(new int[]{i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj});
            queue.add(new int[]{i, j + 1, si, (j + 1 % 10 != 0 ? sj + 1 : sj - 8)});
        }
        return  res;
    }
}

DFS:递归调用至条件

深度优先搜索: 可以理解为暴力法模拟机器人在矩阵中的所有路径。DFS 通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推。
剪枝:在搜索中,遇到数位和超出目标值、此元素已访问,则应立即返回,称之为 可行性剪枝 。
算法解析:
递归参数: 当前元素在矩阵中的行列索引 i 和 j ,两者的数位和 si, sj 。
终止条件: 当 ① 行列索引越界 或 ② 数位和超出目标值 k 或 ③ 当前元素已访问过 时,返回 00 ,代表不计入可达解。
递推工作:
标记当前单元格 :将索引 (i, j) 存入 Set visited 中,代表此单元格已被访问过。
搜索下一单元格: 计算当前元素的 下、右 两个方向元素的数位和,并开启下层递归 。
回溯返回值: 返回 1 + 右方搜索的可达解总数 + 下方搜索的可达解总数,代表从本单元格递归搜索的可达解总数。

class Solution {
    int m, n, k;
    boolean[][] visited;
    public int movingCount(int m, int n, int k) {
        this.m = m; this.n = n; this.k = k;
        this.visited = new boolean[m][n];
        return dfs(0, 0, 0, 0);
    }
    public int dfs(int i, int j, int si, int sj) {
        if(i >= m || j >= n || k < si + sj || visited[i][j]) return 0;
        visited[i][j] = true;
        return 1 + dfs(i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj) + dfs(i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

带着希望活下去

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值