JZ13 机器人的运动范围
(较难)
题目
描述
示例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
思路1:DFS
本文题意为从 [0,0] 开始遍历到[rows-1, cols-1],遇到数位和大于给定的 threshold 值的坐标位置就相当于死路,也可理解为像是边界一样的墙,此题虽说是可以向上下左右四个方向走,但是其实只要向右或者下走就可以了,这点需要意会,而此题解法又是属于一种很明显的深度优先遍历思想,因此递归的终止条件就可以是遇到内部墙或是超出边界墙,就返回 0,之所以返回 0,是因为本题要求计数可以到达的坐标总个数,因为当前遇到内部墙,因此此坐标的这种情况自然就不应被计数进去,而对于当前坐标没有遇到内部墙,又没有超出边界墙,这时可以返回其子情况的计数结果 + 1,1 表示的是当前坐标的这种情况。
注意:必须要加一个记录是否 [row, col] 坐标被访问过的标识数组,例如 boolean[][] visited
数组,因为其递归的子情况,下递归、右递归可能出现重复计数过同一坐标的情况,因此要进行标识,这也是进行深度优先遍历务必要考虑的一件事。
实现
public class JZ13机器人的运动范围 {
int threshold = 0;
int rows = 0;
int cols = 0;
boolean[][] visited = null;
public int movingCount(int threshold, int rows, int cols) {
this.threshold = threshold;
this.rows = rows;
this.cols = cols;
this.visited = new boolean[rows][cols];
return moving(0, 0);
}
public int moving(int row, int col) {
//返回:位数不符合、边界、访问过
if (digitSum(row, col) > threshold
|| row >= rows || col >= cols
|| visited[row][col]) return 0;
//标注这个格子被访问过
visited[row][col] = true;
//子情况 + 当前情况的1次
return moving(row + 1, col) + moving(row, col + 1) + 1;
}
public int digitSum(int num1, int num2) {
int sum = 0;
String total = "" + num1 + num2;
char[] digits = total.toCharArray();
for (char digit : digits) {
sum += Integer.parseInt(digit + "");
}
return sum;
}
}
思路2:BFS
BFS 的思想也十分基础, 借助一个队列实现,之前文章讲解过 BFS 的思路(Java实现【邻接矩阵、邻接表的创建、遍历(DFS,BFS)】+图解+完整代码,当时是用图结构来写的,而这里无非就是向下向右两条路线,可理解为出度为 2 的图),这里不再赘述。
实现
public class Test {
public int movingCount(int threshold, int rows, int cols) {
boolean[][] visited = new boolean[rows][cols];
int count = 0;
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{0, 0});
while (queue.size() > 0) {
int[] next = queue.poll();
int row = next[0], col = next[1];
//返回:位数不符合、边界、访问过
if (row >= rows || col >= cols || threshold < digitSum(row, col) || visited[row][col])
continue;
//标注这个格子被访问过
visited[row][col] = true;
count++;
//下边坐标
queue.add(new int[]{row + 1, col});
//右边坐标
queue.add(new int[]{row, col + 1});
}
return count;
}
public int digitSum(int num1, int num2) {
int sum = 0;
String total = "" + num1 + num2;
char[] digits = total.toCharArray();
for (char digit : digits) {
sum += Integer.parseInt(digit + "");
}
return sum;
}
}
JZ17 打印从1到最大的n位数
(简单)
题目
描述
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
1、用返回一个整数列表来代替打印
2、n 为正整数
示例
输入:
1
返回值:
[1,2,3,4,5,6,7,8,9]
思路
此题用 Java 语言实现起来十分容易,将读入的 n 位数生成 n 个 9,组成一个数,那么这个数就是当前 n 位数中最大的,那么我们返回 1 到这个数的数组即可。
实现
public class JZ17打印从1到最大的n位数 {
public int[] printNumbers (int n) {
int digit = Integer.parseInt(n + "");
String maxString = "";
for (int i = 0; i < digit; i++) {
maxString += "9";
}
int max = Integer.parseInt(maxString);
int[] res = new int[max];
for (int i = 0; i < res.length; i++) {
res[i] = i + 1;
}
return res;
}
}