面试题13. 机器人的运动范围
题目:
思路:
【1】首先明确限制:
1.是从【0,0】开始移动
2.只能上下左右移动【但不能超出边界】
3.不能踏入坐标的位数之后比K大的位置
【2】思路一:考虑广度搜索,通过用队列存储下一个可达的地址,然后再队列中拿出那些地址的下一个可达地址。其中只要用数组表示那些地址已经走过了即可【保证不重复走同一个位置】。但是需要额外开辟一个数组用于存储数据,而且还要对坐标构建一个结构,这些都需要花费一定的空间。好处是一个循环便能解决。
【3】思路二:考虑深度搜索,利用递归的方式实现,通过传入坐标为参数,可以避免对坐标构建,同时也避免了开辟队列的内存空间,但是需要对调用栈不断加深【这也是需要空间的,好处是调用完会释放】,通过leetcode运行结果,这种明显花费时间更少,所用空间也更少,估计是调用栈不深的缘故吧。
代码展示:
//面试题13. 机器人的运动范围 public class Offer { public static void main(String[] args) { Random random = new Random(); int n = random.nextInt(100)+1; int m = random.nextInt(100)+1; int k = random.nextInt(20)+1; System.out.println(Method1(m,n,k)); } // 思路一:BFS(广度优先搜索),通过队列,把当前位置能够达到的下一个位置添加的队列里面 // 从而达到以点扩大到面的程度 public static int Method1(int m, int n, int k){ //临时变量visited记录格子是否被访问过 boolean[][] visited = new boolean[m][n]; int res = 0; //创建一个队列,保存的是访问到的格子坐标,是个二维数组 Queue<int[]> queue = new LinkedList<>(); //从左上角坐标[0,0]点开始访问,add方法表示把坐标 // 点加入到队列的队尾 queue.add(new int[]{0, 0}); while (queue.size() > 0) { //这里的poll()函数表示的是移除队列头部元素,因为队列 // 是先进先出,从尾部添加,从头部移除 int[] x = queue.poll(); int i = x[0], j = x[1]; //i >= m || j >= n是边界条件的判断,k < sum(i, j)判断当前格子坐标是否 // 满足条件,visited[i][j]判断这个格子是否被访问过 if (i >= m || j >= n || k < sum(i, j) || visited[i][j]){ continue; } //标注这个格子被访问过 visited[i][j] = true; res++; //把当前格子下边格子的坐标加入到队列中 queue.add(new int[]{i + 1, j}); //把当前格子右边格子的坐标加入到队列中 queue.add(new int[]{i, j + 1}); } return res; } //思路二:DFS(深度优先搜索),通过利用递归,先走到最底层,先遍历完一条线再遍历其他线 public static int Method2(int m, int n, int k){ //临时变量visited记录格子是否被访问过 boolean[][] visited = new boolean[m][n]; return dfs(0, 0, m, n, k, visited); } public static int dfs(int i, int j, int m, int n, int k, boolean[][] visited) { // i >= m || j >= n是边界条件的判断, // k < sum(i, j)判断当前格子坐标是否满足条件, // visited[i][j]判断这个格子是否被访问过 if (i >= m || j >= n || k < sum(i, j) || visited[i][j]){ return 0; } //标注这个格子被访问过 visited[i][j] = true; // 沿着当前格子的右边和下边继续访问, // 如果画图的话会明显的发现只要每个点都沿着右边和下边遍历,就会遍历到全部 return 1 + dfs(i + 1, j, m, n, k, visited) + dfs(i, j + 1, m, n, k, visited); } //计算两个坐标数字的和 private static int sum(int i, int j) { int sum = 0; while (i != 0) { sum += i % 10; i /= 10; } while (j != 0) { sum += j % 10; j /= 10; } return sum; } }