机器人的运动范围

题目描述

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

解法一:

假设机器人当前位置为(i,j),其可以去的位置为上(i-1,j)、下(i+1,j)、左(i,j-1)和右(i,j+1)。很明显我们可以通过回溯法来求解,当走到的点数位和超过k或者超出了边界,则退回到上一个节点,继续去遍历别的节点。回溯法的重点是要建立一个标志数组来标记哪些点已经被遍历过。

public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {
        boolean[] flag = new boolean[matrix.length];
        //初始化标志矩阵
        for(int i = 0; i < flag.length; i++) {
            flag[i] = true;
        }
        //遍历每一个格子,找到第一个存在要求路径的格子时停止
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < cols; j++) {
                if(hasNext(matrix, rows, cols, str, i, j, 0, flag)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean hasNext(char[] matrix, int rows, int cols, char[] str, int i, int j, int k, boolean[] flag) {
        int index = i * cols + j;
                //矩阵边上格子的限定,i、j的限定要在index之前,否则index会溢出
        if(i >= rows || i < 0 || j < 0 || j >= cols || matrix[index] != str[k] || flag[index] == false) {
            return false;
        }
        if(k == str.length - 1) {
            return true;
        }
                //将进入过的节点进行标记
        flag[index] = false;
        if(hasNext(matrix, rows, cols, str, i + 1, j, k + 1, flag) || 
           hasNext(matrix, rows, cols, str, i - 1, j, k + 1, flag) ||
           hasNext(matrix, rows, cols, str, i, j + 1, k + 1, flag) ||
           hasNext(matrix, rows, cols, str, i, j - 1, k + 1, flag)) {
            return true;
        }
                //若不符合条件,将标记释放,以便于回退后仍可进入该格子
        flag[index] = true;
        return false;
    }
}

上面的程序先将标志数组置为0,将遍历到的但不满足数位和约束的点置为1,遍历到的满足数位和约束条件的点置为2。最后统计置为2的点的个数即可。
由于java中形参传递的是引用的引用,直接操作的话会对原数据产生影响,所以递归回退的时候flag数组不会被重置。

解法二:

与解法一原理相同,但是每次递归时均记录已符合条件的节点个数。

public class Solution {
    public int movingCount(int threshold, int rows, int cols)
    {
        int count = 0;
        int[] flag = new int[rows * cols];
        //初始化标志数组
        for(int i = 0; i < flag.length; i++) {
            flag[i] = 0;
        }
        count = search(threshold, rows, cols, 0, 0, flag);
        return count;
        
    }
    public int search(int threshold, int rows, int cols, int i, int j, int[] flag) {
        int index = i * cols + j;
        int count = 0;
        if(i < 0 || i >= rows || j < 0 || j >= cols || flag[index] > 0) {
            return 0;
        }
        flag[index] = 1;
        /**由于满足条件的点必定是连通的,所以可以通过连通点来遍历得到所有满足的点,对于不满足的点,不再检查其四周的点*/
        /**之所以必定连通是因为所求的为机器人路径上的点*/
        if(lessThanThreshold(threshold, i, j)) {
            count = 1 + search(threshold, rows, cols, i + 1, j, flag)
            + search(threshold, rows, cols, i - 1, j, flag)
            + search(threshold, rows, cols, i, j + 1, flag)
            + search(threshold, rows, cols, i, j - 1, flag);
        }
        return count;
    }
    /**判断数位和是否小于thread*/
    public boolean lessThanThreshold(int threshold, int i, int j) {
        int count = 0;
        while(i % 10 != 0) {
            count += i % 10;
            i /= 10;
        }
        while(j % 10 != 0) {
            count += j % 10;
            j /= 10;
        }
        return count > threshold ? false : true;
    }
}

你可能感兴趣的:(机器人的运动范围)