二进制矩阵中的最短畅通路径
1.题目
小R最近在玩一个迷宫游戏,游戏的目标是在一个 n x n 的二进制矩阵 grid 中找到一条从左上角 (0, 0) 到右下角 (n - 1, n - 1) 的畅通路径。畅通路径必须满足以下条件:
- 路径经过的所有单元格的值都是
0。 - 路径中相邻的单元格必须在 8 个方向之一上连通(相邻单元格之间共享一条边或一个角)。
你需要帮助小R找到最短的畅通路径长度。如果不存在这样的路径,返回 -1。
2.测试样例
样例1:
输入:
grid = [[0,1],[1,0]]
输出:2
样例2:
输入:
grid = [[0,0,0],[1,1,0],[1,1,0]]
输出:4
样例3:
输入:
grid = [[1,0,0],[1,1,0],[1,1,0]]
输出:-1
3.思路
典型的BFS问题,可以从(0,0)位置起始,进行BFS搜索,每次将队首元素的八个方向依次入队,判断这些位置是否合法,如果合法,加入到队列之中,同时更新距离,直至队列为空,最后判断从(0,0)到(n-1,m-1)的距离是否为0,如果是0说明没有路径,否则即为最短路径的值。
算法步骤:
- 用
dist存储起点到其他各个点的距离。 - 从起点开始广度优先遍历地图。
- 当地图遍历完,就求出了起点到各个点的距离,输出
dist[n-1][m-1]即可。
4.代码
import java.util.Arrays;
import java.util.Queue;
import java.util.LinkedList;
public class Main {
// 一个内部类,用来存储每个位置的x,y坐标
static class pair{
private int x;
private int y;
public pair(int x, int y){
this.x = x;
this.y = y;
}
}
public static int solution(int[][] grid) {
int n = grid.length;
int m = grid[0].length;
// 判断特殊情况,如果只有一个元素且不为1,那么直接返回1即可
if(n==1 && m==1 && grid[0][0]==0) return 1;
// 如果起始位置和终点有一个是1,说明路径不畅通,返回-1
if(grid[0][0]==1 || grid[n-1][m-1]==1) return -1;
// x和y的八个偏移量
int[] dx = {0, 1, 1, 1, 0, -1, -1, -1};
int[] dy = {1, 1, 0, -1, -1, -1, 0, 1};
// st代表(x,y)是否被使用过,dist代表起点到(x,y)的距离
int[][] st = new int[n][m];
for(int i=0; i<n; i++) Arrays.fill(st[i], 0);
int[][] dist = new int[n][m];
for(int i=0; i<n; i++) Arrays.fill(dist[i], 0);
Queue<pair> q = new LinkedList<>();
// 将起始位置入队
q.add(new pair(0, 0));
while(!q.isEmpty()){
pair t = q.peek();
q.poll();
// 依次判断八个位置是否合法,如果非法则continue,否则入队,并将距离和状态更新
for(int i=0; i<8; i++){
int a = t.x + dx[i];
int b = t.y + dy[i];
if(a<0 || a>=n || b<0 || b>=m) continue;
if(grid[a][b] == 1) continue;
if(st[a][b] == 1) continue;
dist[a][b] = dist[t.x][t.y] + 1;
st[a][b] = 1;
q.add(new pair(a, b));
}
}
// 最后判断一下是否可以到达终点
if(dist[n-1][m-1] == 0) return -1;
return dist[n-1][m-1]+1;
}
public static void main(String[] args) {
System.out.println(solution(new int[][]{{0, 1}, {1, 0}}) == 2);
System.out.println(solution(new int[][]{{0, 0, 0}, {1, 1, 0}, {1, 1, 0}}) == 4);
System.out.println(solution(new int[][]{{1, 0, 0}, {1, 1, 0}, {1, 1, 0}}) == -1);
}
}
二进制之和
1. 问题描述
小U和小R喜欢探索二进制数字的奥秘。他们想找到一个方法,将两个二进制字符串相加并以十进制的形式呈现。这个过程需要注意的是,他们的二进制串可能非常长,所以常规的方法可能无法处理大数。小U和小R希望你帮助他们设计一个算法,该算法能在保证时间复杂度不超过O(n^2)的前提下,返回两个二进制字符串的十进制求和结果。
2. 测试样例
样例1:
输入:
binary1 = "101" ,binary2 = "110"
输出:'11'
样例2:
输入:
binary1 = "111111" ,binary2 = "10100"
输出:'83'
样例3:
输入:
binary1 = "111010101001001011" ,binary2 = "100010101001"
输出:'242420'
样例4:
输入:
binary1 = "111010101001011" ,binary2 = "10010101001"
输出:'31220'
样例5:
输入:
binary1 = "11" ,binary2 = "1"
输出:'4'
3. 解题思路
这道题如果用c/c++写的话就需要用到高精度算法来模拟加减的过程,但是如果用java或者python语言的话,这两种语言自带大数相加的功能,所以直接套用即可。
4. 代码
import java.math.BigInteger;
public class Main {
public static String solution(String binary1, String binary2) {
BigInteger num1 = new BigInteger(binary1, 2);
BigInteger num2 = new BigInteger(binary2, 2);
BigInteger sum = num1.add(num2);
return sum.toString();
}
public static void main(String[] args) {
System.out.println(solution("101", "110").equals("11"));
System.out.println(solution("111111", "10100").equals("83"));
System.out.println(solution("111010101001001011","100010101001").equals("242420"));
}
}