剑指offer_机器人运动的范围 (C++_DFS、BFS,递推迭代)

原题链接
在这里插入图片描述

1.DFS

1.首先将机器人放到第一格位置,从第一格判断结束后分别对周围所有格子在进行判断。同时为了防止格子被重复判断,要新建立一个bool类数组来标记格子是否走过。
2.为了使代码的逻辑性更强,我们把这个过程分成三部,用三个函数来实现,①从起点开始,往下递归,②判断其是否越界以及格子是否被走过,③将格子所在的行列的数字拆分后求和与题中的threshold对比

注意:
这里不需要将标记走过的bool数组还原,因为这个题是记录走过的格子数。如果还原了,在其他路径上走过这个格子的话就重复计算了。详情对比题目见矩阵路径
矩阵路径的这个题目需要还原数组。因为不同路径可以走到相同的位置。只要不是所有位置都相同,这个两条不通的路径,矩阵路径的题干如下:
在这里插入图片描述
这里不在介绍这道题,思路相同。

C++代码

class Solution {
public:
    int movingCount(int m, int n, int k) {
        if(k==0){
            return 1;
        }
        vector<vector<bool>>flag(m,vector<bool>(n,true));
        int ret=0;
        dfs(0,0,m,n,flag,k,ret);
        return ret;
    }
private:
    vector<vector<int>>dirct={{0,1},{1,0},{0,-1},{-1,0}};
    void dfs(int row,int col,int ROW,int COL,vector<vector<bool>>&flag,int sum,int&ret){
        if(Iegal(row,col,ROW,COL,sum,flag)){
            flag[row][col]=false;
            ret++;
            for(int i=0;i<4;i++){
                dfs(row+dirct[i][0],col+dirct[i][1],ROW,COL,flag,sum,ret);
            }
        }
    }
    bool Iegal(int row,int col,int ROW,int COL,int k,vector<vector<bool>>&flag){
        return (row>=0&&row<ROW)&&(col>=0&&col<COL)&&(sum(row)+sum(col)<=k)&&(flag[row][col]==true);
    }
    int sum(int num){
        int ret=0;
        while(num){
            ret+=num%10;
            num=num/10;
        }
        return ret;
    }
};

在这里插入图片描述

时间复杂度 O(MN) : 最差情况下,机器人遍历矩阵所有单元格,此时时间复杂度为 O(MN) 。
空间复杂度 O(MN)

2.BFS

BFS/DFS的区别: 两者目标都是遍历整个矩阵,不同点在于搜索顺序不同。DFS 是朝一个方向走到底,再回退,以此类推;BFS 则是按照类似“平推”的方式向前一层一层的搜索。

实现BFS通常需要使用队列。

  1. 队列头部数据出队列,判断是不是符合题干。
  2. bool数组标记这个位置已经走过
  3. 将这个位置周围没有被bool数字标记的其他方向的合法格子入队。并且将这个格子周围的格子使用bool数组标记。
  4. 当队列的大小为0时跳出循环。

在这个过程中每一次入队都代表机器人可以跳过这个格子,所以入队次数就算最后的答案。

C++代码

class Solution {
    vector<vector<int>>dirct={{0,1},{1,0},{0,-1},{-1,0}};   
public:
    int movingCount(int m, int n, int k) {
        if(k==0){
            return 1;
        }
        queue<vector<int>>q;
        vector<vector<bool>>flag(m,vector<bool>(n,true));
        int ret=1;
        q.push({0,0});
        flag[0][0]=false;
        while(!q.empty()){
            vector<int>pos=q.front();
            q.pop();
            for(int i=0;i<4;i++){
                int nextrow=pos[0]+dirct[i][0];
                int nextcol=pos[1]+dirct[i][1];
                if(Iegal(nextrow,nextcol,m,n,k,flag)){
                    flag[nextrow][nextcol]=false;
                    q.push({nextrow,nextcol});
                    ret++;
                }
            }
        }
        return ret;
    }
private:
    bool Iegal(int row,int col,int ROW,int COL,int k,vector<vector<bool>>&flag){
        return (row>=0&&row<ROW)&&(col>=0&&col<COL)&&(sum(row)+sum(col)<=k)&&(flag[row][col]==true);
    }

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

在这里插入图片描述
时间复杂度O(MN)
空间复杂度O(MN)

3.递推迭代

根据上面的层序遍历代码分析可知。
设机器人的位置在[i,j]那么他一定是从[i-1,j]或者[i,j-1]移动来的,所以机器人每次的移动可以优化向左或向下移动。

标记数组定义为vector<vector< int>>其中0代表不可达,1代表可达。
最后的答案就算标记数组元素和。

C++代码

class Solution {
public:
    int movingCount(int m, int n, int k) {
        if(k==0){
            return 1;
        }
        vector<vector<int>>flag(m,vector<int>(n,0));
        flag[0][0]=1;
        int ret=1;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if((i==0&&j==0)||(sum(i)+sum(j)>k)){
                    continue;
                }
                else{
                    if(i-1>=0){
                        flag[i][j]|=flag[i-1][j];
                    }
                    if(j-1>=0){
                        flag[i][j]|=flag[i][j-1];
                    }
                    ret+=flag[i][j];
                }
            }
        }
        return ret;
    }
private:
    int sum(int num){
        int ret=0;
        while(num>0){
            ret+=num%10;
            num/=10;
        }
        return ret;
    }
};

在这里插入图片描述
时间复杂度 O(MN) : 最差情况下,机器人遍历矩阵所有单元格,此时时间复杂度为 O(MN) 。
空间复杂度 O(MN)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

NUC_Dodamce

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

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

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

打赏作者

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

抵扣说明:

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

余额充值