刷题笔记~

一、DFS

 

1、LeetCode No1254

1、题目中要求封闭岛屿的数目,即有多少片被1包围的0。我们首先想到边界上的0是肯定不会被1包围的,连着边界上的0肯定也是不会被1包围的,所以要去除边界上的0和连着边界的0的干扰。因此遍历四个边界,边界上的每个点向下去做深度搜索,若是0的话改成1,排除干扰。

2、此时二维数组中剩下的0肯定都是被1包围的了,遍历这个二维数组,遇到0,封闭岛数量加1

同时深度遍历,把连着的0变成1.

3、深度遍历(DFS):传入遍历到的点,上下左右做深度搜索,直到越界或者不满足条件()该点为水域),是陆地的点改成水域,这要就可以不用维护visited数组(用于记录已经遍历过的点)。

技巧总结:

①边界可以排除干扰

②岛问题可以改变已经遍历过的点的值,避免重复遍历

③可以用一个visited数组记录遍历过的点避免重复遍历

④DFS深度遍历 上下左右深度遍历,不满足条件的return,满足条件的改值。

⑤从边界开始DFS,而不是从里面开始到边界

class Solution {
        public int closedIsland(int[][] grid) {
            //把边界上的0变成1 ,连着边界的0变成1 剩下的连着的0就是一个封闭岛屿
            int rows = grid.length;
            int col = grid[0].length;
            int res = 0;
            for (int i = 0; i < rows; i++) {
                dfs(grid, i, 0);
                dfs(grid, i, col - 1);
            }

            for (int i = 0; i < col; i++) {
                dfs(grid, 0, i);
                dfs(grid, rows - 1, i);
            }

            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < col; j++) {
                    if (grid[i][j] == 0) {
                        res++;
                        dfs(grid, i, j);
                    }
                }
            }
            return res;
        }

        public void dfs(int[][] grid, int i, int j) {
            if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length) {
                return;
            }

            if (grid[i][j] == 1) {
                return;
            }

            grid[i][j] = 1;
            dfs(grid, i + 1, j);
            dfs(grid, i - 1, j);
            dfs(grid, i, j + 1);
            dfs(grid, i, j - 1);
        }
    }

 2、LeetCode No130

此题和Leecode No1254类似,1254题是要记录封闭岛数量,因此边界陆地被更改无影响,中间记录过一次导数量后,这边导都要改值,避免重复遍历。

本题要返回二维数组,因此返回时边界的值不能被改变,可以用一个特殊的字符来标识(边界开始深度遍历来改值),最后改回来。由于不用计数,所以中间的都是封闭岛,可以直接遍历改值。

此题还可以用并查集来做,见并查集小节。

二、并查集

并查集技巧:

主函数中判断需要合并的两个样本(边界先合并,思考是上下左右找合并,还是左上还是啥),调用并查集模板UnionFind中的union方法进行合并或动态初始化上下左右找,满足条件的合并(条件:不越界,有size,代表节点不同)。

UnionFind模板中:

①样本包成一个圈,样本指向自己样本可以用数组或者坐标的下标表示 int[][] parents或map      为了小挂大,记录圈的大小以及控制是否被初始化过 int[] size;  为了结构扁平化  int[] help;  初始的圈数量(样本数量 或0)

②初始化 

静态初始化:样本是本身,传入数组长度初始化     样本是坐标,坐标转换成数组下标初始化

动态初始化:给一个条件,传入动态初始化UnionFind中connet方法中初始化(若该样本没有被初始化过),上下左右看有没有可以合并的(越界、不可以连的size0,已经连过的代表节点一样),输出一个结果,构造方法只初始化大小。

③union方法  

不在一个圈的合并   代表节点不是一个

有的需要判断,size为0的不合并

size小的挂size大的

④findParent方法

找代表节点的方法,help[]中的都指向代表节点,使结构扁平化。

1、LeetCode No547

 1、其中题目中给的二维数组isConnected[i][j]表示i城市和j城市相连。则本题的样本就是各个城市,i城市和j城市包成一个圈。

2、主函数中判断满足条件需要合并成一个圈的两个样本。调用并查集模板UnionFind中的union方法进行合并。

2、LeetCode No130

此题在DFS章节使用DSF解,也可以使用并查集来解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值