【剑指offer】13. 机器人的运动范围

170 阅读4分钟

题目描述

在这里插入图片描述

在这里插入图片描述

// 13. 机器人的运动范围
// 力扣
// 地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。
// 一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、
// 右、上、下移动一格(不能移动到方格外),也不能进入行坐标
// 和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能
// 够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [
// 35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

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

题解

// 力扣

// 本题使用的方法为深度优先搜索(DFS),方法和12题的回溯法很像,
// 但其实回溯法是DFS的特殊情况。
// 执行用时:2 ms, 在所有 Java 提交中击败了43.58%的用户
// 内存消耗:35.4 MB, 在所有 Java 提交中击败了84.10% 的用户
class Solution {
	private int rows;
	private int cols;
	private int k;
	private int[][] digitSum;
	private static final int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};

	private int count = 0;

	// 解题函数
    public int movingCount(int m, int n, int k) {
		this.rows = m;
		this.cols = n;
		this.k = k;
        if (rows == 0 || cols == 0) // 行或者列其中一个为0,则返回0
            return 0;
		if (k == 0) // 如果k为0,则能到达位置只有(0,0)这第一个位置
            return 1;
        boolean[][] marked = new boolean[rows][cols]; // 定义与搜索矩阵同尺寸的标记矩阵marked
		dfs(marked, 0, 0);  // 开始深度优先搜索递归,起始位置为左上角(0,0)
		return count;  // 搜索完毕,返回计数
    }

	// 定义搜索函数
	// 输入标记矩阵marked,行索引r(初始化为0),列索引c(初始化为0)
	private void dfs(boolean[][] marked, int r, int c) {
		if (r < 0 || r >= rows || c < 0 || c >= cols)  // 超过正常矩阵边界,返回
			return;
		if (marked[r][c])  // 该位置已被遍历过,返回
			return;
		if ((digitSum(r) + digitSum(c)) > k)  // 超过数位和的上限,返回
			return;
		
		count++;  // 如果满足条件,成功计数一次
		marked[r][c] = true;  // 该位置标记为已被使用
		// System.out.println(markedToString(marked));  // 打印marked矩阵
		for (int[] n : next)
			dfs(marked, r + n[0], c + n[1]);
	}

	// 定义函数:位数之和
    public int digitSum(int n) {
        int n0 = n / 1000000000;
        int n1 = n % 1000000000 / 100000000;
        int n2 = n % 100000000 / 10000000;
        int n3 = n % 10000000 / 1000000;
        int n4 = n % 1000000 / 1000000;
        int n5 = n % 100000 / 10000;
        int n6 = n % 10000 / 1000;
        int n7 = n % 1000 / 100;
        int n8 = n % 100 / 10;
        int n9 = n % 10;

        int sum = n0 + n1 + n2 + n3 + n4 + n5 + n6 +n7 + n8 + n9;
        return sum;
    }
	
	// 打印marked的toString函数(不是必须)
    public String markedToString(boolean[][] marked) {
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < marked.length; i++) {
			res.append("[");
			for (int j = 0; j < marked[0].length; j++) {
				if (marked[i][j])
					res.append(" true ");
				else 
					res.append(" false ");
			}
			res.append("]");
			res.append("\r\n");
        }
        return res.toString();
    }
}
// 牛客
// 思路和力扣是一样的
// 运行时间:11ms
// 占用内存:9692k

public class Solution {
    private int rows;
    private int cols;
    private int threshold;
    private int[][] digitSum;
    private static final int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
    private int count = 0;
    
    public int movingCount(int threshold, int rows, int cols) {
        this.rows = rows;
        this.cols = cols;
        this.threshold = threshold;
        if (rows == 0 || cols == 0)
            return 0;
        if (threshold == 0)
            return 1;
        boolean[][] marked = new boolean[rows][cols];
        dfs(marked, 0, 0);
        return count;
    }
    
    private void dfs(boolean[][] marked, int r, int c) {
        if (r < 0 || r >= rows || c < 0 || c >= cols)  
            return;
        if (marked[r][c])  
            return;
        if ((digitSum(r) + digitSum(c)) > threshold)  
            return;

        count++;  
        marked[r][c] = true;  
        // System.out.println(markedToString(marked));  
        for (int[] n : next)
            dfs(marked, r + n[0], c + n[1]);
    }

	// 定义函数:位数之和
    public int digitSum(int n) {
        int n0 = n / 1000000000;
        int n1 = n % 1000000000 / 100000000;
        int n2 = n % 100000000 / 10000000;
        int n3 = n % 10000000 / 1000000;
        int n4 = n % 1000000 / 1000000;
        int n5 = n % 100000 / 10000;
        int n6 = n % 10000 / 1000;
        int n7 = n % 1000 / 100;
        int n8 = n % 100 / 10;
        int n9 = n % 10;

        int sum = n0 + n1 + n2 + n3 + n4 + n5 + n6 +n7 + n8 + n9;
        return sum;
    }
    
    // 打印marked的toString函数(不是必须)
    public String markedToString(boolean[][] marked) {
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < marked.length; i++) {
            res.append("[");
            for (int j = 0; j < marked[0].length; j++) {
                if (marked[i][j])
                    res.append(" true ");
                else 
                    res.append(" false ");
            }
            res.append("]");
            res.append("\r\n");
        }
        return res.toString();
    }
}