leetcode 14天图论基础
day : 1
733. 图像渲染
思路:dfs,需要注意的是:如果newColor = 中心点的数值,不能dfs,不然就会一直递归,此时,可知不需要改变,直接将原数组返回就行
class Solution {
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
int aim = image[sr][sc];
int m = image.length, n = image[0].length;
if(aim == newColor) ; //key, 不然会一直递归,栈溢出:java.lang.StackOverflowError
else
dfs(image, sr, sc, aim, m, n, newColor);
return image;
}
public void dfs(int[][] image, int x, int y, int aim, int m, int n, int newColor){
if(x < 0 || y < 0 || x >= m || y >= n || image[x][y] != aim)
return;
image[x][y] = newColor;
dfs(image, x, y - 1, aim, m, n, newColor); //上
dfs(image, x, y + 1, aim, m, n, newColor); //下
dfs(image, x - 1, y, aim, m, n, newColor); //左
dfs(image, x + 1, y, aim, m, n, newColor); //右
}
}
200. 岛屿数量
思路: dfs,分别以每个点为中心进行遍历,如果中心点为1,则此处必然有一个岛,一直四个方向dfs,并在遍历过程中将每个1都置为0,以防重复,直到找到所以边界点,则一个岛便找到了
version 1.0
class Solution {
boolean isLandsFlag = false; //用一个flag来标记找到1,也就是这里有一个岛
public int numIslands(char[][] grid) {
int m = grid.length, n = grid[0].length;
int ans = 0;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
dfs(grid, i, j, m, n);
if(isLandsFlag)
ans++;
isLandsFlag = false;//恢复
}
}
return ans;
}
public void dfs(char[][] grid, int x, int y, int m, int n){
if(x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == '0')
return;
grid[x][y] = '0';
isLandsFlag = true;
dfs(grid, x - 1, y, m, n);
dfs(grid, x + 1, y, m, n);
dfs(grid, x, y - 1, m, n);
dfs(grid, x, y + 1, m, n);
}
}
version 2.0
//仅仅将m,n换为数组.length,以减少递归函数的变量个数,但是效果却变差了
class Solution {
boolean isLandsFlag = false;
public int numIslands(char[][] grid) {
int ans = 0;
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid[0].length; j++){
dfs(grid, i, j);
if(isLandsFlag)
ans++;
isLandsFlag = false;
}
}
return ans;
}
public void dfs(char[][] grid, int x, int y){
if(x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] == '0')
return;
grid[x][y] = '0';
isLandsFlag = true; //一旦有陆地,那这片必然有岛屿
dfs(grid, x - 1, y);
dfs(grid, x + 1, y);
dfs(grid, x, y - 1);
dfs(grid, x, y + 1);
}
}
由上面可知将数组大小用变量存着速度更快, 终极版如下
version 3.0
class Solution {
public int numIslands(char[][] grid) {
int m = grid.length, n = grid[0].length;
int ans = 0;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
//找到1才进行调用dfs
if(grid[i][j] == '1'){
dfs(grid, i, j, m, n);
ans++;
}
}
}
return ans;
}
public void dfs(char[][] grid, int x, int y, int m, int n){
if(x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == '0')
return;
grid[x][y] = '0';
dfs(grid, x - 1, y, m, n);
dfs(grid, x + 1, y, m, n);
dfs(grid, x, y - 1, m, n);
dfs(grid, x, y + 1, m, n);
}
}
day : 2
695. Max Area of Island
思路:dfs, 找到土地,则必有岛,对遇到的每块土地记录,并置0,最后一直取最值,即可
class Solution {
private int ans = 0;
public int maxAreaOfIsland(int[][] grid) {
int m = grid.length, n = grid[0].length;
int maxans = 0;
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++){
if(grid[i][j] == 1){
dfs(grid, i, j, m, n);
maxans = Math.max(maxans, ans);
ans = 0;
}
}
return maxans;
}
public void dfs(int[][] grid, int i, int j, int m, int n){
if(i < 0 || j < 0 || i >= m || j >= n || grid[i][j] == 0)
return;
grid[i][j] = 0;
ans++;
dfs(grid, i - 1, j, m, n);
dfs(grid, i + 1, j, m, n);
dfs(grid, i, j - 1, m, n);
dfs(grid, i, j + 1, m, n);
}
}
1254. 统计封闭岛屿的数目
思路: 此题与前面不同在于,并没有说矩阵四周布满了水,而且水为1,土地为0,所以岛屿只可能在中间区域,不会在边缘,在dfs过程中,如果探出了边界,就要把flag置flase, 表示虽然回溯了,但是这不是一个封闭岛屿。
class Solution {
private boolean flag;
public int closedIsland(int[][] grid) {
int ans = 0;
int m = grid.length, n = grid[0].length;
flag = true;
for(int i = 1; i < m - 1; i++){
for(int j = 1; j < n - 1; j++){
if(grid[i][j] == 0){
dfs(grid, i, j, m, n);
if(flag) ans++;
flag = true;
}
}
}
return ans;
}
public void dfs(int[][] grid, int i, int j, int m, int n){
if(i < 0 || j < 0 || i >= m || j >= n){
flag = false;
return;
}
if(grid[i][j] == 1) //遇水返回
return;
grid[i][j] = 1;
dfs(grid, i - 1, j, m, n);
dfs(grid, i + 1, j, m, n);
dfs(grid, i, j - 1, m, n);
dfs(grid, i, j + 1, m, n);
}
}
day : 3
1020. 飞地的数量
思路1:
dfs, 用一个flag来标记是否是岛屿,一旦越界则表示可以走通,置flase,遇到0就返回,定一个成员变量cnt,遇到1就++,
并把1置为0,表示已经走过了,如果是岛屿就把ans 加 cnt,否则cnt清零
class Solution {
boolean isIsand;
int cnt;
public int numEnclaves(int[][] grid) {
int ans = 0;
isIsand = true;
cnt = 0;
int m = grid.length, n = grid[0].length;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(grid[i][j] == 1){
dfs(grid, i, j, m, n);
if(isIsand) ans += cnt;
cnt = 0;
isIsand = true;
}
}
}
return ans;
}
public void dfs(int[][] grid, int i, int j, int m, int n){
if(i < 0 || j < 0 || i >= m || j >= n){//越界
isIsand = false;
return;
}
if(grid[i][j] == 0)
return;
if(grid[i][j] == 1)
cnt++;
grid[i][j] = 0;
dfs(grid, i - 1, j, m, n);
dfs(grid, i + 1, j, m, n);
dfs(grid, i, j - 1, m, n);
dfs(grid, i, j + 1, m, n);
}
}
思路2:
一块土地能走出去就不计数,故,可以对边界先进行dfs,将所有能出去的全部清零,最后遍历剩余数组,遇到1就ans++即可,因为剩余的一定都走不出去
class Solution {
public int numEnclaves(int[][] grid) {
int ans = 0;
int m = grid.length, n = grid[0].length;
for(int i = 0; i < m; i++){
dfs(grid, i, 0, m, n);
dfs(grid, i, n - 1, m, n);
}
for(int j = 0; j < n; j++){
dfs(grid, 0, j, m, n);
dfs(grid, m - 1, j, m, n);
}
for(int i = 1; i < m - 1; i++){
for(int j = 1; j < n - 1; j++){
if(grid[i][j] == 1){
ans++;
}
}
}
return ans;
}
public void dfs(int[][] grid, int i, int j, int m, int n){
if(i < 0 || j < 0 || i >= m || j >= n || grid[i][j] == 0)
return;
grid[i][j] = 0;
dfs(grid, i - 1, j, m, n);
dfs(grid, i + 1, j, m, n);
dfs(grid, i, j - 1, m, n);
dfs(grid, i, j + 1, m, n);
}
}
1905. 统计子岛屿
思路:可以参考下图,我的code没有他的beats多,但也浅显易懂吧。若1和2中的都是土地就把2此处值2,那么遍历对2中的每个2dfs,遇到1,表示此处1中为水,故不是子岛,flag置false,如果遇到2置0,继续dfs,
class Solution {
boolean flag;//表示是否是子岛
public int countSubIslands(int[][] grid1, int[][] grid2) {
int m = grid1.length, n = grid1[0].length;
int ans = 0;
flag = true;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(grid1[i][j] == 1 && grid2[i][j] == 1)
grid2[i][j] = 2;//如果是2表示都是土地
}
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(grid2[i][j] == 2){ //遇到2才dfs
dfs(grid2, i, j, m, n);
if(flag) ans++;
flag = true;
}
}
}
return ans;
}
public void dfs(int[][] grid2, int i, int j, int m, int n){
if(i < 0 || j < 0 || i >= m || j >= n || grid2[i][j] == 0)
return;
//遇到1表示此处grid1中为水,直接false,return
if(grid2[i][j] == 1){
flag = false; //注意这里如果return就不要将grid2[i][j]置0
return; //如果不return,继续dfs或者把grid2[i][j]置0再dfs都可
}
grid2[i][j] = 0;
dfs(grid2, i - 1, j, m, n);
dfs(grid2, i + 1, j, m, n);
dfs(grid2, i, j - 1, m, n);
dfs(grid2, i, j + 1, m, n);
}
}
//他的code
class Solution {
int rc;
int cc;
public int countSubIslands(int[][] grid1, int[][] grid2) {
rc = grid1.length;
cc = grid1[0].length;
for (int i = 0; i < rc; i++) {
for (int j = 0; j < cc; j++) {
if (grid2[i][j] == 1) {
grid2[i][j] += grid1[i][j];
}
}
}
int res = 0;
for (int i = 0; i < rc; i++) {
for (int j = 0; j < cc; j++) {
// DFS BFS任选一个
if (grid2[i][j] == 2 && fill(grid2, i, j)) {
res++;
}
}
}
return res;
}
private boolean fill(int[][] grid, int i, int j) {
if (i < 0 || i >= rc || j < 0 || j >= cc) {
return true;
}
if (grid[i][j] != 2) {
return grid[i][j] == 0;
}
grid[i][j] = 0;
boolean down = fill(grid, i - 1, j);
boolean up = fill(grid, i + 1, j);
boolean right = fill(grid, i, j - 1);
boolean left = fill(grid, i, j + 1);
return down & up & right & left;
}
}
后续待更新