733. 图像渲染
简化问题,只从一个点分析:【初始点 / 满足条件的一点】
- 只需要判断上下左右,是否满足要修改的条件
- 记录每个点是否修改过,因为如果修改后的目标值与初始值相同,就可能导致陷入修改循环
- 如果上下左右的点满足条件,那么就以该点为起始点,进入递归环节
class Solution {
public int[][] floodFill(int[][] image, int sr, int sc, int color) {
//获取行列
int row = image.length;
int col = image[0].length;
//设置标记数组
boolean [][] flag = new boolean[row][col];
//初始化
for(int i = 0; i < row; i++){
Arrays.fill(flag[i], true);
}
//要改变的像素
int old = image[sr][sc];
//调用方法
uColor(image, sr, sc, old, color, flag);
//返回数组
return image;
}
//对一个特定点考虑
public void uColor(int [][] arr, int r, int c, int old, int color, boolean [][] flag){
//将当前位置更新
arr[r][c] = color;
flag[r][c] = false;
//对上判断
if(r > 0 ){
if(arr[r - 1][c] == old && flag[r - 1][c]){
uColor(arr, r - 1, c, old, color, flag);
}
}
//对下判断
if(r < arr.length - 1){
if(arr[r + 1][c] == old && flag[r + 1][c]){
uColor(arr, r + 1, c, old, color, flag);
}
}
//对左判断
if(c > 0){
if(arr[r][c - 1] == old && flag[r][c - 1]){
uColor(arr, r, c - 1, old, color, flag);
}
}
//对右判断
if(c < arr[0].length - 1){
if(arr[r][c + 1] == old && flag[r][c + 1]){
uColor(arr, r, c + 1, old, color, flag);
}
}
}
}
695. 岛屿的最大面积
遇到一个岛屿,就记录它的面积,与最大面积比较,更新最大面积
记录面积的方法就是,将当前为1的地方置零,然后递归它的上下左右,最后返回计数
class Solution {
public int[][] floodFill(int[][] image, int sr, int sc, int color) {
//获取行列
int row = image.length;
int col = image[0].length;
//设置标记数组
boolean [][] flag = new boolean[row][col];
//初始化
for(int i = 0; i < row; i++){
Arrays.fill(flag[i], true);
}
//要改变的像素
int old = image[sr][sc];
//调用方法
uColor(image, sr, sc, old, color, flag);
//返回数组
return image;
}
//对一个特定点考虑
public void uColor(int [][] arr, int r, int c, int old, int color, boolean [][] flag){
//将当前位置更新
arr[r][c] = color;
flag[r][c] = false;
//对上判断
if(r > 0 ){
if(arr[r - 1][c] == old && flag[r - 1][c]){
uColor(arr, r - 1, c, old, color, flag);
}
}
//对下判断
if(r < arr.length - 1){
if(arr[r + 1][c] == old && flag[r + 1][c]){
uColor(arr, r + 1, c, old, color, flag);
}
}
//对左判断
if(c > 0){
if(arr[r][c - 1] == old && flag[r][c - 1]){
uColor(arr, r, c - 1, old, color, flag);
}
}
//对右判断
if(c < arr[0].length - 1){
if(arr[r][c + 1] == old && flag[r][c + 1]){
uColor(arr, r, c + 1, old, color, flag);
}
}
}
}
617. 合并二叉树
采用深度优先遍历,利用一个新的二叉树来保存结果,利用两棵树的结点来构造结果树,递归创建左右子树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
//存在空树
if(root1 == null){
return root2;
}
if(root2 == null){
return root1;
}
//结果树
TreeNode res = new TreeNode(root1.val + root2.val);
//递归左子树
res.left = mergeTrees(root1.left, root2.left);
//递归右子树
res.right = mergeTrees(root1.right, root2.right);
//返回结果
return res;
}
}
116. 填充每个结点的下一个右侧结点的指针
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
//根结点为空
if(root == null){
return null;
}
//创建一个队列,用于记录一层的元素
Queue<Node> queue = new LinkedList<Node>();
queue.add(root);
//广搜遍历二叉树
while(!queue.isEmpty()){
//该层元素的个数
int size = queue.size();
//通过循环将该层元素连接起来,并把下一层元素添加到结合中
for(int i = 0; i < size; i++){
//取出队首元素
Node node = queue.poll();
//如果当前层在队列里有剩余元素,那么就将当前元素指向队首的剩余元素
if(i < size - 1){
node.next = queue.peek();
}
//将当前结点的子节点添加到队列中
if(node.left != null){
queue.add(node.left);
}
if(node.right != null){
queue.add(node.right);
}
}
}
//返回二叉树的根结点
return root;
}
}
542. 01 矩阵
class Solution {
/**
利用队列广度优先搜索,记录所有零的位置,然后把距离为1的地方
全部更新,然后逐步扩大范围,直至遍历完整个矩阵
*/
//记录四个移动方向
int [][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public int[][] updateMatrix(int[][] mat) {
//n行m列
int n = mat.length;
int m = mat[0].length;
//保存结果
int [][] res = new int[n][m];
//记录是否遍历过
boolean [][] seen = new boolean[n][m];
//队列辅助广搜
Queue<int []> queue = new LinkedList<int []>();
//将所有零的位置添加到队列中
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(mat[i][j] == 0){
queue.add(new int[]{i, j});
seen[i][j] = true;
}
}
}
//广度优先搜索
while(!queue.isEmpty()){
//取出当前的坐标
int [] local = queue.poll();
int i = local[0];
int j = local[1];
//从当前位置的四个方向开始拓展
for(int k = 0; k < 4; k++){
int ni = i + dirs[k][0];
int nj = j + dirs[k][1];
//新位置是否为没遍历过的 1
if(ni >= 0 && ni < n && nj >=0 && nj < m && !seen[ni][nj]){
res[ni][nj] = res[i][j] + 1;
seen[ni][nj] = true;
queue.add(new int[]{ni, nj});
}
}
}
//返回结果
return res;
}
}
994. 腐烂的橘子
class Solution {
/**
与01矩阵类似,利用广度优先搜索
记录下所有腐烂橘子的位置,每分钟向周围扩展一次,直至不能再扩展
记录扩展次数,最后遍历格子中的所有橘子,如果存在新鲜橘子返回-1
否则返回计数
*/
public int orangesRotting(int[][] grid) {
//四个方向移动
int [][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
//利用队列辅助遍历橘子
Queue<int []> queue = new LinkedList<int []>();
//数组的大小
int n = grid.length;
int m = grid[0].length;
//遍历数组,将所有腐烂橘子位置记录下来
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(grid[i][j] == 2){
queue.add(new int[]{i, j});
}
}
}
//计数
int count = 0;
int size = queue.size();
//如果有腐烂橘子就遍历数组
while(!queue.isEmpty()){
//获取当前位置
int [] place = queue.poll();
int i = place[0], j = place[1];
//向四个方向去扩展
for(int d = 0; d < 4; d++){
//新位置
int ni = i + dirs[d][0];
int nj = j + dirs[d][1];
//判断是否为新橘子
if(ni >= 0 && ni < n && nj >=0 && nj < m && grid[ni][nj] == 1){
//将新腐烂的橘子的位置记录下来
grid[ni][nj] = 2;
queue.add(new int[]{ni, nj});
}
}
//这一分钟是当前这轮所有腐烂的橘子都扩展完
if(--size == 0){
count++;
//下轮扩展的次数
size = queue.size();
}
}
//遍历数组,查看是否所有橘子都腐烂了
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(grid[i][j] == 1){
return -1;
}
}
}
//都腐烂了或者都是新鲜的【因为最后有一次无效扩展】
return count == 0 ? 0 : count - 1;
}
}