BFS解决floodfill算法
图像渲染

题目解析 :就是将与起始位置相同颜色相同并且连通 (上下左右)的位置颜色修改成color(指定颜色)
思想 :从起始位置开始不断递归上下左右方向 ,将与其颜色相同位置修改颜色,并且从这个修改的位置上下左右与起始颜色相同位置也要修改 ,就这样不断修改,直到连通区域都修改完成就结束了细节问题:
此时这里可能修改前后颜色一样,此时这种情况直接返回即可(防止死递归)

java
class Solution {
int[] dx = {1,-1,0,0};
int[] dy = {0,0,1,-1};
int m,n;
int begin;//要修改颜色
int end;//修改成的颜色
public int[][] floodFill(int[][] image, int sr, int sc, int color) {
m = image.length;
n = image[0].length;
begin = image[sr][sc];
end = color;
//如果要修改的和修改后的一样直接返回即可
if(image[sr][sc] == color){
return image;
}
//从sr,sc开始找
dfs(image,sr,sc);
image[sr][sc] = color;
return image;
}
public void dfs(int[][] image,int sr,int sc){
for(int k = 0;k < 4;k++){
int x = sr + dx[k];
int y = sc + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && image[x][y] == begin){
image[x][y] = end;
dfs(image,x,y);//下一层
}
}
}
}
岛屿数量

题目解析 :就是找出岛屿数量(1的连通块的数量)
思想:从1岛屿开始标记其所在连通块,防止重复统计

java
class Solution {
int ret;
int m,n;
int[] dx = {1,-1,0,0};
int[] dy = {0,0,1,-1};
boolean[][] visited;//标记已经遍历过的位置
public int numIslands(char[][] grid) {
//直接从边界出发即可
m = grid.length;
n = grid[0].length;
visited = new boolean[m][n];
for(int i = 0;i < m;i++){
for(int j = 0;j < n;j++){
if(visited[i][j] == false && grid[i][j] == '1'){
ret++;
dfs(grid,i,j);
}
}
}
return ret;
}
public void dfs(char[][] grid,int i,int j){
for(int k = 0; k < 4;k++){
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && visited[x][y] == false && grid[x][y] == '1'){
visited[x][y] = true;
dfs(grid,x,y);
}
}
}
}
岛屿的最大面积

题目解析 :有很多个岛屿,求出最大岛屿面积(这个岛屿1的数量)
思想 :每次从一个未走过的1开始一个新的岛屿可以使用一个全局 count 统计此时岛屿数量即可
java
class Solution {
int ret;
int count;
int m,n;
int[] dx = {1,-1,0,0};
int[] dy = {0,0,1,-1};
boolean[][] visited;
public int maxAreaOfIsland(int[][] grid) {
m = grid.length;
n = grid[0].length;
visited = new boolean[m][n];
for(int i = 0;i < m;i++){
for(int j = 0;j < n;j++){
if(visited[i][j] == false && grid[i][j] == 1){
visited[i][j] = true;
count++;
dfs(grid,i,j);
//更新结果
ret = Math.max(ret,count);
count = 0;
}
}
}
return ret;
}
public void dfs(int[][] grid,int i,int j){
for(int k = 0;k < 4;k++){
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && visited[x][y] == false && grid[x][y] == 1){
visited[x][y] = true;
count++;
dfs(grid,x,y);
}
}
}
}
被围绕的区域

题目解析 :将被X完全围住的O修改成X,未被完全围住O不修改
思想 :正难则反,由于里面的O存在不是被X围住的不可以修改先将这些未被围住的O修改成 ' . ',最后剩余的被围住的O,将剩余O修改成X,将 ' . '修改回来

java
class Solution {
int[] dx = {1,-1,0,0};
int[] dy = {0,0,1,-1};
int m,n;
public void solve(char[][] board) {
m = board.length;
n = board[0].length;
//1. 将与边界相邻的O(未被围住的)修改 .
for(int i = 0;i < m;i++){
if(board[i][0] == 'O'){
board[i][0] = '.';
dfs(board,i,0);
}
if(board[i][n-1] == 'O'){
board[i][n-1] = '.';
dfs(board,i,n-1);
}
}
for(int i = 0; i < n;i++){
if(board[0][i] == 'O'){
board[0][i] = '.';
dfs(board,0,i);
}
if(board[m-1][i] == 'O'){
board[m-1][i] = '.';
dfs(board,m-1,i);
}
}
//2.最后将.修改成O
for(int i = 0;i < m;i++){
for(int j = 0;j < n;j++){
if(board[i][j] == 'O'){
board[i][j] = 'X';
}else if(board[i][j] == '.'){
board[i][j] = 'O';
}
}
}
}
//将未被X围住的O修改成.
public void dfs(char[][] board,int i,int j){
for(int k = 0;k < 4;k++){
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O'){
board[x][y] = '.';
dfs(board,x,y);
}
}
}
}
太平洋大西洋水流问题

题目解析 :水往低处流,找出所有既可以流向太平洋又可以流向大西洋的位置
思想 :使用两个标记数组,标记可以流向那个海洋,最后将都可以流向的位置进行通统计返回即可从边界开始进行扩展,扩展比当前高的位置,高的位置可以向下流,不断以对应边界为起点进行扩展

java
class Solution {
int[] dx = {1,-1,0,0};
int[] dy = {0,0,1,-1};
int m,n;
public List<List<Integer>> pacificAtlantic(int[][] heights) {
m = heights.length;
n = heights[0].length;
boolean[][] pac = new boolean[m][n];
boolean[][] atl = new boolean[m][n];
List<List<Integer>> ret = new ArrayList<>();
//从大西洋和太平洋开始找可以流向它的位置
//都可以流向的位置就是要找的结果
//太平洋
for(int i = 0; i < n;i++){
dfs(heights,0,i,pac);
}
for(int i = 0;i < m;i++){
dfs(heights,i,0,pac);
}
//大西洋
for(int i = 0;i < n;i++){
dfs(heights,m-1,i,atl);
}
for(int i = 0;i < m;i++){
dfs(heights,i,n-1,atl);
}
for(int i = 0;i < m;i++){
for(int j = 0;j < n;j++){
if(pac[i][j] && atl[i][j]){
List<Integer> tem = new ArrayList<>();
tem.add(i);
tem.add(j);
ret.add(tem);
}
}
}
return ret;
}
public void dfs(int[][] heights,int i,int j,boolean[][] vis){
vis[i][j] = true;
for(int k = 0;k < 4;k++){
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && heights[x][y] >= heights[i][j]){
dfs(heights,x,y,vis);
}
}
}
}
扫雷游戏
题目解析 :给了一个起始点击点,周围有雷就停止扩展,没有雷周围未被扩展的位置可以作为起始点扩展
思想:先统计雷的个数,有雷就更新结果停止扩展,没有就将其周围没有扩展位置作为起点开始扩展
此时这里周围是八个方向,因此可以使用两个dx和dy极坐标表示


java
class Solution {
int[] dx = { 0, 0, 1, -1, -1, 1, -1, 1 };
int[] dy = { 1, -1, 0, 0, 1, -1, -1, 1 };
int m, n;
public char[][] updateBoard(char[][] board, int[] click) {
m = board.length;
n = board[0].length;
int x = click[0];
int y = click[1];
if (board[x][y] == 'M') {
board[x][y] = 'X';
return board;
}
dfs(board, x, y);
return board;
}
public void dfs(char[][] board, int i, int j) {
//统计地雷的个数
int count = 0;
//上,下,左,右,和所有4个对角线
for(int k = 0;k < 8;k++){
int x = i + dx[k];
int y = j + dy[k];
//统计周围地雷个数
if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'M'){
count++;
}
}
//周围没有雷的位置继续展开
if(count == 0){
board[i][j] = 'B';
for(int k = 0;k < 8;k++){
int x = i + dx[k];
int y = j + dy[k];
//统计周围地雷个数
if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'E'){
dfs(board,x,y);
}
}
}else{
board[i][j] = (char)(count+'0');
return;
}
}
}
衣橱整理

题目解析 :找出有多少可以整理的格子,整理格子两坐标数位之和 <= cnt才可以整理,并且整理过程中选择向下 / 向右移动
思想:直接从(0,0)开始dfs扩展即可,判定是否满足数位要求,并且使用vis标记已经整理过的位置

java
class Solution {
int ret;
int m, n,cnt;
boolean[][] vis;
int[] dx = {1,-1,0,0};
int[] dy = {0,0,1,-1};
public int wardrobeFinishing(int _m, int _n, int _cnt) {
m = _m;
n = _n;
cnt = _cnt;
vis = new boolean[m][n];
dfs(0, 0);
return ret;
}
public void dfs(int i, int j) {
ret++;
vis[i][j] = true;
for(int k = 0;k < 4;k++){
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && vis[x][y] == false && check(x,y) <= cnt){
dfs(x,y);
}
}
}
public int check(int x, int y) {
int tem = 0;
while (x != 0) {
tem += x % 10;
x /= 10;
}
while (y != 0) {
tem += y % 10;
y /= 10;
}
return tem;
}
}