剑指Offer(六十六):二维数组的运动范围(Java版)

本文探讨了一种机器人在受限制的网格环境中移动的问题,通过深度优先搜索(DFS)和广度优先搜索(BFS)算法,计算在给定阈值条件下能到达的格子数量。两种方法对比,展示了如何避免重复计数并优化空间和时间复杂度。
摘要由CSDN通过智能技术生成

描述

地上有一个 rows 行和 cols 列的方格。坐标从 [0,0] 到 [rows-1,cols-1] 。一个机器人从坐标 [0,0] 的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于 threshold 的格子。 例如,当 threshold 为 18 时,机器人能够进入方格 [35,37] ,因为 3+5+3+7 = 18。但是,它不能进入方格 [35,38] ,因为 3+5+3+8 = 19 。请问该机器人能够达到多少个格子?

数据范围: 0 \le threshold \le 15 \0≤threshold≤15 ,1 \le rows,cols \le 100 \1≤rows,cols≤100

进阶:空间复杂度 O(nm) \O(nm) ,时间复杂度 O(nm) \O(nm)

示例1

输入:1,2,3

返回值:3

示例2

输入:0,1,3

返回值:1

示例3

输入:10,1,100

返回值:29

说明:

[0,0],[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10],[0,11],[0,12],[0,13],[0,14],[0,15],[0,16],[0,17],[0,18],[0,19],[0,20],[0,21],[0,22],[0,23],[0,24],[0,25],[0,26],[0,27],[0,28] 这29种,后面的[0,29],[0,30]以及[0,31]等等是无法到达的

示例4

输入:5,10,10

返回值:21

第一种解法

使用dfs(深度优先搜索)来解决,需要注意的一点。得防止重复的点二次计数。代码如下

int[][] arr = null;
int count = 0;
public int firstMovingCount(int threshold, int rows, int cols) {
    if(rows < 1 && cols < 1){
        return count;
    }
    if(threshold < 0){
        return count;
    }
    arr = new int[rows][cols];
    dsf(threshold,rows,cols,0,0);
    return count;
}


public void dsf(int threshold, int rows, int cols,int row,int col){
    if(row < 0 || row >= rows || col < 0 || col >= cols || arr[row][col] == 1){
        return;
    }
    if(check(row) + check(col) > threshold){
        return;
    }
    arr[row][col] = 1;
    count++;
    dsf(threshold,rows,cols,row+1,col);
    dsf(threshold,rows,cols,row-1,col);
    dsf(threshold,rows,cols,row,col+1);
    dsf(threshold,rows,cols,row,col-1);
}


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

第二种解法 

使用bfs(广度优先搜索)来解决。对于bfs的特性,采用队列来实现是最好的,因为队列是先进先出,离他最近的访问完之后加入到队列中,最先入队的也是最先出队的,代码如下

int[][] arr = null;
int count = 0;

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


public int secondMovingCount(int threshold, int rows, int cols) {
    if(rows < 1 && cols < 1){
        return count;
    }
    if(threshold < 0){
        return count;
    }
    arr = new int[rows][cols];
    Queue<int[]> queue = new LinkedList<>();
    queue.add(new int[]{0,0});
    while (!queue.isEmpty()){
        int[] poll = queue.poll();
        int i = poll[0];
        int j = poll[1];
        if(i >= rows || j >= cols || arr[i][j] == 1 || (check(i) + check(j) > threshold)){
            continue;
        }
        arr[i][j] = 1;
        count++;
        queue.add(new int[]{i+1,j});
        queue.add(new int[]{i,j+1});
    }
    return count;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值