题目描述
地上有一个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;
}
}