题目描述: 给定一个代表游戏板的二维字符矩阵。 ‘M’ 代表一个未挖出的地雷,‘E’ 代表一个未挖出的空方块,‘B’ 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字(‘1’ 到 ‘8’)表示有多少地雷与这块已挖出的方块相邻,‘X’ 则表示一个已挖出的地雷。
现在给出在所有未挖出的方块中(‘M’或者’E’)的下一个点击位置(行和列索引),根据以下规则,返回相应位置被点击后对应的面板:
思路: BFS。需要统计压入队列的每个位置周围八个方向是否有炸弹,如果存在炸弹,则该位置的值变为周围炸弹的数目,且该点将不再压入队列中继续BFS。只有周围炸弹为零时,该位置才压入队列,继续搜索。设置vis[][]数组,统计周围炸弹数目时,不需要考虑是否该点被遍历过(压入过队列),压入队列时,需考虑。
class Solution {
public:
struct point{
int x, y;
};
int dir[8][2] = {1,0,-1,0,0,1,0,-1,-1,-1,1,1,-1,1,1,-1};
vector> updateBoard(vector>& board, vector& click) {
int n = board.size(), m = board[0].size();
if(board[click[0]][click[1]] == 'M') {
board[click[0]][click[1]] = 'X';
//cout<<"11111111"< Q;
vector> vis(n, vector(m, 0));
Q.push(point{click[0], click[1]});
vis[click[0]][click[1]] = 1;
while(!Q.empty()) {
point q = Q.front();
Q.pop();
int cnt = 0;
for(int i = 0; i < 8; i++) {
int x = q.x + dir[i][0];
int y = q.y + dir[i][1];
if(x >= 0 && x < n && y >= 0 && y < m && board[x][y] == 'M')
cnt++;
}
if(cnt == 0) {
board[q.x][q.y] = 'B';
for(int i = 0; i < 8; i++) {
int x = q.x + dir[i][0];
int y = q.y + dir[i][1];
if(x >= 0 && x < n && y >= 0 && y < m && vis[x][y] == 0){
Q.push(point{x, y});
vis[x][y] = 1;
}
}
}
else
board[q.x][q.y] = ('0' + cnt);
}
return board;
}
};
题目描述: 给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。
请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。
提示: 输出坐标的顺序不重要;m 和 n 都小于150。
思路: BFS逆向扩散。从两片海洋开始逆流,如果可以逆流到,就标记为1,然后检查两个海洋都可以逆流到的区域。
class Solution {
public:
struct point {
int x, y;
};
int dir[4][2] = {1,0,-1,0,0,1,0,-1};
vector> pacificAtlantic(vector>& matrix) {
vector> ans;
if(matrix.size() == 0 || matrix[0].size() == 0)
return ans;
int n = matrix.size(), m = matrix[0].size();
queue Q1, Q2;
vector> vis1(n, vector(m, 0));
vector> vis2(n, vector(m, 0));
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(i == 0 || j == 0) {
Q1.push(point{i, j});
vis1[i][j] = 1;
}
if(i == n - 1 || j == m - 1){
Q2.push(point{i, j});
vis2[i][j] = 1;
}
}
}
while(!Q1.empty()) {
point q = Q1.front();
Q1.pop();
for(int i = 0; i < 4; i++) {
int x = q.x + dir[i][0];
int y = q.y + dir[i][1];
if(x >= 0 && x < n && y >= 0 && y < m && matrix[x][y] >= matrix[q.x][q.y] && vis1[x][y] == 0) {
Q1.push(point{x, y});
vis1[x][y] = 1;
}
}
}
while(!Q2.empty()) {
point q = Q2.front();
Q2.pop();
for(int i = 0; i < 4; i++) {
int x = q.x + dir[i][0];
int y = q.y + dir[i][1];
if(x >= 0 && x < n && y >= 0 && y < m && matrix[x][y] >= matrix[q.x][q.y] && vis2[x][y] == 0) {
Q2.push(point{x, y});
vis2[x][y] = 1;
}
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(vis1[i][j] == 1 && vis2[i][j] == 1) {
vector tmp(2, 0);
tmp[0] = i;
tmp[1] = j;
ans.push_back(tmp);
}
}
}
return ans;
}
};
题目描述: 你现在手里有一份大小为 N x N 的『地图』(网格) grid,上面的每个『区域』(单元格)都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地,你知道距离陆地区域最远的海洋区域是是哪一个吗?请返回该海洋区域到离它最近的陆地区域的距离。
我们这里说的距离是『曼哈顿距离』( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个区域之间的距离是 |x0 - x1| + |y0 - y1| 。
如果我们的地图上只有陆地或者海洋,请返回 -1。
思路: BFS。用距离数组dis[][]表示所有点距离陆地的曼哈顿距离,则原本为陆地的点的曼哈顿距离为0,海洋的曼哈顿距离初始化为-1。从所有陆地出发,然后从陆地开始向外进行BFS式的扩散,然后每扩散一层就将计数器(即曼哈顿距离)加一,不断“填海造陆”直到整个地图再也不存在海洋为止,并且每更新一次计数器,同时更新最大的曼哈顿距离的值,最终返回最大值。
class Solution {
public:
struct point {
int x, y;
};
int dir[4][2] = {1,0,-1,0,0,1,0,-1};
int maxDistance(vector>& grid) {
int n = grid.size(), m = grid[0].size();
vector> dis(n, vector(m, -1));
queue Q;
int cnt = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(grid[i][j] == 1) {
Q.push(point{i, j});
dis[i][j] = 0;
cnt++;
}
}
}
if(cnt == 0 || cnt == n * m)
return -1;
int ans = 0;
while(!Q.empty()) {
point q = Q.front();
Q.pop();
for(int i = 0; i < 4; i++) {
int x = q.x + dir[i][0];
int y = q.y + dir[i][1];
if(x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 0 && dis[x][y] == -1) {
dis[x][y] = dis[q.x][q.y] + 1;
ans = max(ans, dis[x][y]);
Q.push(point{x, y});
}
}
}
return ans;
}
};
题目描述: 你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’ 。每个拨轮可以自由旋转:例如把 ‘9’ 变为 ‘0’,‘0’ 变为 ‘9’ 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 ‘0000’ ,一个代表四个拨轮的数字的字符串。
列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回 -1。
思路: BFS。把问题转化成最短路径问题,这里的最短路径指的是由起始状态"0000"转换为目标状态所需要的最少变换次数,那么就可以用BFS来解决这一类最短路径问题。首先,先将deadends中的死亡数字存入到unordered_map中,将其值映射为1,方便之后查找得到的状态是否存在于deadends中。对于每一个状态,它可以扩展到最多 8 个状态,即将它的第 i = 0, 1, 2, 3 位增加 1 或减少 1,将这些状态中没有搜索过并且不在 deadends 中的状态全部加入到队列中,并继续进行搜索。
class Solution {
public:
int openLock(vector& deadends, string target) {
unordered_map mp;
for(int i = 0; i < deadends.size(); i++) {
mp[deadends[i]] = 1;
}
queue Q;
unordered_map vis;
unordered_map dis;
if(mp["0000"] == 1)
return -1;
Q.push("0000");
vis["0000"] = 1;
while(!Q.empty()) {
string q = Q.front();
Q.pop();
if(q == target)
return dis[q];
for(int i = 0; i < 4; i++) {
string tmp1 = q, tmp2 = q;
if(q[i] == '9') {
tmp1[i] = '0';
tmp2[i] = '8';
}
else if(q[i] == '0') {
tmp1[i] = '1';
tmp2[i] = '9';
}
else {
tmp1[i] += 1;
tmp2[i] -= 1;
}
if(mp[tmp1] == 0 && vis[tmp1] == 0) {
Q.push(tmp1);
vis[tmp1] = 1;
dis[tmp1] = dis[q] + 1;
}
if(mp[tmp2] == 0 && vis[tmp2] == 0) {
Q.push(tmp2);
vis[tmp2] = 1;
dis[tmp2] = dis[q] + 1;
}
}
}
return -1;
}
};
题目描述: 在一块 N x N 的棋盘 board 上,从棋盘的左下角开始,每一行交替方向,按从 1 到 N * N的数字给方格编号。玩家从棋盘上的方格 1 (总是在最后一行、第一列)开始出发。每一次从方格 x 起始的移动都由以下部分组成:
你选择一个目标方块 S,它的编号是 x+1,x+2,x+3,x+4,x+5,或者 x+6,只要这个数字 <= N * N。
如果 S 有一个蛇或梯子,你就移动到那个蛇或梯子的目的地。否则,你会移动到 S。
在 r 行 c 列上的方格里有 “蛇” 或 “梯子”;如果 board[r][c] != -1,那个蛇或梯子的目的地将会是 board[r][c]。
注意,你每次移动最多只能爬过蛇或梯子一次:就算目的地是另一条蛇或梯子的起点,你也不会继续移动。
返回达到方格 N*N 所需的最少移动次数,如果不可能,则返回 -1。
思路: 将二维转换为一维,避免计算坐标,见change()函数。再进行BFS计算最少移动次数(即最小距离)。
class Solution {
public:
void change(vector>& board, vector& , int N) {
int num = 1, x = 0, y = N - 1;
int dir = 1; // dir == 1为从左向右,dir== -1 为从右向左。
while(num <= N * N) {
[num] = board[y][x];
num++;
if(dir == 1 && x == N - 1) {
dir = -1;
y--;
}
else if(dir == -1 && x == 0){
dir = 1;
y--;
}
else
x += dir;
}
return ;
}
int snakesAndLadders(vector>& board) {
int N = board.size();
vector dis(N * N + 1, -1);
vector (N *N + 1, 0);
change(board, , N);
queue Q;
Q.push(1);
dis[1] = 0;
while(!Q.empty()) {
int q = Q.front();
Q.pop();
for(int i = 1; i <= 6; i++) {
int pp = q + i;
if(pp > N * N)
continue;
if([pp] != -1)
pp = [pp];
if(dis[pp] != -1)
continue;
dis[pp] = dis[q] + 1;
Q.push(pp);
}
}
return dis[N * N];
}
};