面试题13: 机器人的运动范围

面试题13: 机器人的运动范围

题目

地上有一个m行n列的方格。一个机器人从坐标(0,0)的格子开始移动,它每次可以向左、右、上、下移动一格,

但不能进入行坐标和列坐标的数位之和大于K的格子。例如,当k为18时,机器人能够进入方格(35,37),因为

3+5+3+7 = 18。但它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子

书本版本(错误示范)

这个思路是错误,但也能当成一个典型反面教训吧,记录下

int movingCount(int threshold, int rows, int cols)
{
    if(threshold < 0 || rows < 1 || cols < 1) return 0;
    int row = 0;
    int col = 0;
    int count = rows * cols;
    bool* visited = new bool[rows * cols];
    memset(visited, 0, rows * cols);

    movingCountCore(threshold,rows,cols,row,col,visited,count);
    return count;
    
}

int bitSum(int num1, int num2)
{
    int sum = 0;
    int temp = 0;
    while(num1 != 0){
        temp = num1 % 10;
        sum += temp;
        num1 /= 10;
    }
    while(num2 != 0){
        temp = num2 % 10;
        sum += temp;
        num2 /= 10;
    }
    return sum;
}

void movingCountCore(int threshold, int rows, int cols, int row, int col, bool* visited,int & count)
{
    //if(visited[row * cols + col] == true) return;

    if(row >= 0 && row < rows && col >= 0 && col < cols 
      && visited[row * cols + col] == false){
        if(bitSum(row,col) > threshold){
        visited[row * cols + col] = true;
        -- count;
        return ;
        }
        movingCountCore(threshold,rows,cols,row + 1, col ,visited,count);
        movingCountCore(threshold,rows,cols,row - 1, col ,visited,count);
        movingCountCore(threshold,rows,cols,row, col - 1, visited,count);
        movingCountCore(threshold,rows,cols,row, col - 1, visited,count);
    }
}

LeetCode 版本

count 个数不能用减的, 要用加的,因为这题如果用减的,有的位置访问不到,是不能正确算出实际的数字

采用 count = 1 + 四个方位的递归

class Solution{
public:
int bitSum(int m, int n){
    int sum = 0;
    int temp = 0;
    while(m != 0){
        temp = m % 10;
        sum += temp;
        m /= 10;
    }
    while(n != 0){
        temp = n % 10;
        sum += temp;
        n /= 10;
    }
    return sum;
}
int movingCountCore(int row ,int col, int m,int n, int k, bool * visited)
{
    int count = 0;
    if(row >=0 && row < m && col >= 0 && col < n 
      && bitSum(row,col) <= k && visited[row * n + col] == false){
          visited[row * n + col ] = true;
          count = 1 + movingCountCore(row + 1,col,m,n,k,visited) 
                    + movingCountCore(row - 1,col,m,n,k,visited)
                    + movingCountCore(row,col + 1,m,n,k,visited)
                    + movingCountCore(row,col - 1,m,n,k,visited);
    }
    return count;
}
int movingCount(int m, int n, int k){
    if(m < 1 || n < 1 || k < 0) return 0;
    bool *visited = new bool[m*n];
    memset(visited,0,m*n);
    int count = 0;
    count = movingCountCore(0,0,m,n,k,visited);
    delete[] visited;
    return count;
}
};

看了k神题解,我又行了

100内的数位和,因为数字每次加1,设 x (x 属于 [0,98]) x的数位和为sx
则 x + 1 的数位和 为 (x + 1) % 10 == 0 ? sx - 8 : sx + 1;

经证明 因为从(0,0)开始,每次只要走右(横坐标 增加) 和走下(纵坐标 增加)就能遍历成功
这也是为什么我感觉四个方向会有重复的原因,直觉还是准的(笑)

算法2:DFS

时间:O(mn)空间O(mn)

class Solution{
public:
int dfs(int row, int col, int m, int n, int si, int sj, int k, vector<vector<bool>> &visited){
    if(row >= m || col >= n || visited[row][col] || (si + sj) > k)  return 0;
    visited[row][col] = true;
    return 1 + dfs(row+1,col,m,n,(row + 1) % 10 == 0? si-8: si + 1, sj,k,visited)
             + dfs(row,col+1,m,n,si,(col + 1) % 10 == 0?sj-8:sj+1,k,visited);
}
int movingCount(int m, int n, int k){
    vector<vector<bool>> visited(m,vector<bool>(n, 0));
    return dfs(0,0,m,n,0,0,k,visited);
}
};

算法3:BFS

class Solution{
public:
int movingCount(int m, int n, int k){
    vector<vector<bool>> visited(m,vector<bool>(n,0));
    queue<vector<int>> q;
    int res = 0;
    q.push({0,0,0,0});
    while(!q.empty()){
        vector<int> x = q.front();
        q.pop();
        int i = x[0], j = x[1], si = x[2], sj = x[3];
        if(i>=m || j>= n || si+sj > k ||visited[i][j])continue;//visited[i][j]不能写在前面,因为下标可能是非法的,要先检查下标
        res++;
        visited[i][j] = true;
        q.push({i+1,j,(i+1)%10==0?si-8:si+1,sj});
        q.push({i,j+1,si,(j+1)%10==0?sj-8:sj+1});
    }
    return res;
}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值