【算法训练-搜索算法 一】【DFS网格搜索框架】岛屿数量、岛屿的最大面积、岛屿的周长

news2024/11/13 16:11:50

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是【搜索算法】,使用【数组】这个基本的数据结构来实现,这个高频题的站点是:CodeTop,筛选条件为:目标公司+最近一年+出现频率排序,由高到低的去牛客TOP101去找,只有两个地方都出现过才做这道题(CodeTop本身汇聚了LeetCode的来源),确保刷的题都是高频要面试考的题。
在这里插入图片描述
明确目标题后,附上题目链接,后期可以依据解题思路反复快速练习,题目按照题干的基本数据结构分类,且每个分类的第一篇必定是对基础数据结构的介绍

岛屿数量

来做这道传说中的岛屿数量,我们所熟悉的 **DFS(深度优先搜索)**问题通常是在树或者图结构上进行的。而我们今天要讨论的 DFS 问题,是在一种「网格」结构中进行的。岛屿问题是这类网格 DFS 问题的典型代表。网格结构遍历起来要比二叉树复杂一些,如果没有掌握一定的方法,DFS 代码容易写得冗长繁杂

题干

在这里插入图片描述

解题思路

首先明确下这一类题目该如何求解:

1 网格问题的基本概念

我们首先明确一下岛屿问题中的网格结构是如何定义的,以方便我们后面的讨论。网格问题是由 m×n个小方格组成一个网格,每个小方格与其上下左右四个方格认为是相邻的,要在这样的网格上进行某种搜索。

岛屿问题是一类典型的网格问题。每个格子中的数字可能是 0 或者 1。我们把数字为 0 的格子看成海洋格子,数字为 1 的格子看成陆地格子,这样相邻的陆地格子就连接成一个岛屿
在这里插入图片描述
在这样一个设定下,就出现了各种岛屿问题的变种,包括岛屿的数量、面积、周长等。不过这些问题,基本都可以用 DFS 遍历来解决

2 DFS 的基本结构

网格结构要比二叉树结构稍微复杂一些,它其实是一种简化版的图结构。要写好网格上的 DFS 遍历,我们首先要理解二叉树上的 DFS 遍历方法,再类比写出网格结构上的 DFS 遍历。我们写的二叉树 DFS 遍历一般是这样的:

void traverse(TreeNode root) {
    // 判断 base case
    if (root == null) {
        return;
    }
    // 访问两个相邻结点:左子结点、右子结点
    traverse(root.left);
    traverse(root.right);
}

可以看到,二叉树的 DFS 有两个要素:「访问相邻结点」和「判断 base case」。

  • 第一个要素是访问相邻结点。二叉树的相邻结点非常简单,只有左子结点和右子结点两个。二叉树本身就是一个递归定义的结构:一棵二叉树,它的左子树和右子树也是一棵二叉树。那么我们的 DFS 遍历只需要递归调用左子树和右子树即可。

  • 第二个要素是 判断 base case。一般来说,二叉树遍历的 base case 是 root == null。这样一个条件判断其实有两个含义:一方面,这表示 root 指向的子树为空,不需要再往下遍历了。另一方面,在 root == null 的时候及时返回,可以让后面的 root.leftroot.right 操作不会出现空指针异常。

对于网格上的 DFS,我们完全可以参考二叉树的 DFS,写出网格 DFS 的两个要素:

  1. 首先,网格结构中的格子有多少相邻结点?答案是上下左右四个。对于格子 (r, c) 来说(r 和 c 分别代表行坐标和列坐标),四个相邻的格子分别是 (r-1, c)、(r+1, c)、(r, c-1)、(r, c+1)。换句话说,网格结构是「四叉」的

在这里插入图片描述

  1. 其次,网格 DFS 中的 base case 是什么?从二叉树的 base case 对应过来,应该是网格中不需要继续遍历、grid[r][c] 会出现数组下标越界异常的格子,也就是那些超出网格范围的格子

在这里插入图片描述

这一点稍微有些反直觉,坐标竟然可以临时超出网格的范围?这种方法我称为「先污染后治理」—— 甭管当前是在哪个格子,先往四个方向走一步再说,如果发现走出了网格范围再赶紧返回。这跟二叉树的遍历方法是一样的,先递归调用,发现 root == null 再返回。

这样,我们得到了网格 DFS 遍历的框架代码

void dfs(int[][] grid, int r, int c) {
    // 判断 base case
    // 如果坐标 (r, c) 超出了网格范围,直接返回
    if (!inArea(grid, r, c)) {
        return;
    }
    // 访问上、下、左、右四个相邻结点
    dfs(grid, r - 1, c);
    dfs(grid, r + 1, c);
    dfs(grid, r, c - 1);
    dfs(grid, r, c + 1);
}

// 判断坐标 (r, c) 是否在网格中
boolean inArea(int[][] grid, int r, int c) {
    return 0 <= r && r < grid.length 
        	&& 0 <= c && c < grid[0].length;
}

3 如何避免重复遍历

网格结构的 DFS 与二叉树的 DFS 最大的不同之处在于,遍历中可能遇到遍历过的结点。这是因为,网格结构本质上是一个「图」,我们可以把每个格子看成图中的结点,每个结点有向上下左右的四条边。在图中遍历时,自然可能遇到重复遍历结点
在这里插入图片描述
如何避免这样的重复遍历呢?答案是标记已经遍历过的格子。以岛屿问题为例,我们需要在所有值为 1 的陆地格子上做 DFS 遍历。每走过一个陆地格子,就把格子的值改为 2,这样当我们遇到 2 的时候,就知道这是遍历过的格子了。也就是说,每个格子可能取三个值:

  • 0 —— 海洋格子
  • 1 —— 陆地格子(未遍历过)
  • 2 —— 陆地格子(已遍历过)

我们在框架代码中加入避免重复遍历的语句:

void dfs(int[][] grid, int r, int c) {
    // 判断 base case
    if (!inArea(grid, r, c)) {
        return;
    }
    // 如果这个格子不是岛屿,直接返回
    if (grid[r][c] != 1) {
        return;
    }
    grid[r][c] = 2; // 将格子标记为「已遍历过」
    
    // 访问上、下、左、右四个相邻结点
    dfs(grid, r - 1, c);
    dfs(grid, r + 1, c);
    dfs(grid, r, c - 1);
    dfs(grid, r, c + 1);
}

// 判断坐标 (r, c) 是否在网格中
boolean inArea(int[][] grid, int r, int c) {
    return 0 <= r && r < grid.length 
        	&& 0 <= c && c < grid[0].length;
}

在这里插入图片描述

代码实现

给出代码实现基本档案

基本数据结构数组
辅助数据结构
算法搜索算法
技巧

其中数据结构、算法和技巧分别来自:

  • 10 个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树
  • 10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法
  • 技巧:双指针、滑动窗口、中心扩散

当然包括但不限于以上

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 判断岛屿数量
     * @param grid char字符型二维数组
     * @return int整型
     */
    public int solve (char[][] grid) {
        // 记录岛屿数量
        int count = 0;
        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[0].length; c++) {
                // 找到岛屿入口
                if (grid[r][c] == '1') {
                    // 记录岛屿数量
                    count++;
                    // 发现并设置出完整岛屿轮廓
                    dfsFind(grid, r, c);
                }
            }
        }

        return count;
    }

    private void dfsFind(char[][] grid, int r, int c) {
        // 遍历到边界则返回
        if (!isInArea(grid, r, c)) {
            return;
        }
        // 遍历到非陆地的地方直接返回【海洋以及已探索陆地】
        if (grid[r][c] != '1') {
            return;
        }
        // 遍历过的陆地设置为2,防止重复计数
        grid[r][c] = '2';

        dfsFind(grid, r, c + 1);
        dfsFind(grid, r, c - 1);
        dfsFind(grid, r + 1, c);
        dfsFind(grid, r - 1, c);
    }

    private boolean isInArea(char[][] grid, int r, int c) {
        // 判断当前坐标是否仍然在岛屿范围内
        return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length;
    }
}

复杂度分析

计算岛屿数量的问题通常通过深度优先搜索(DFS)或广度优先搜索(BFS)来解决。以下是使用深度优先搜索(DFS)算法来计算岛屿数量的时间和空间复杂度分析:

时间复杂度: 在最坏情况下,DFS需要访问矩阵中的每个格子一次,因此时间复杂度为O(M*N),其中M是矩阵的行数,N是矩阵的列数。

空间复杂度: 空间复杂度取决于递归调用的深度。在最坏情况下,如果整个矩阵都是陆地,DFS的递归深度可能达到MN,因此空间复杂度为O(MN)。通常,DFS的空间复杂度还包括了用于存储访问标记的数据结构(如一个额外的矩阵或集合),因此实际的空间复杂度可能稍微高一些。

需要注意的是,如果使用迭代而不是递归来实现DFS,可以通过使用栈来降低空间复杂度,但时间复杂度仍然是O(M*N)。

总之,岛屿数量问题的时间复杂度是O(MN),空间复杂度通常为O(MN),但在一些优化的情况下可以降低到O(min(M, N))。这取决于具体的实现方式和问题的输入。

岛屿的最大面积【MID】

接着岛屿数量的题,继续做与之相关的岛屿最大面积的计算

题干

在这里插入图片描述

解题思路

这道题目只需要对每个岛屿做 DFS 遍历,求出每个岛屿的面积就可以了。求岛屿面积的方法也很简单,代码如下,每遍历到一个格子,就把面积加一

int area(int[][] grid, int r, int c) {  
    return 1 
        + area(grid, r - 1, c)
        + area(grid, r + 1, c)
        + area(grid, r, c - 1)
        + area(grid, r, c + 1);
}

代码实现

给出代码实现基本档案

基本数据结构数组
辅助数据结构
算法搜索算法
技巧

其中数据结构、算法和技巧分别来自:

  • 10 个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树
  • 10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法
  • 技巧:双指针、滑动窗口、中心扩散

当然包括但不限于以上

class Solution {
    public int maxAreaOfIsland(int[][] grid) {
         int maxArea = 0;
        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[0].length; c++) {
                // 找到岛屿入口
                if (grid[r][c] == 1) {
                    // 发现并设置出完整岛屿轮廓
                    int area = area(grid, r, c);
                    // 比较并设置最大面积
                    maxArea = Math.max(maxArea, area);
                }
            }
        }
          return maxArea;
    }

     private int area(int[][] grid, int r, int c) {
        // 遍历到边界则返回0
        if (!isInArea(grid, r, c)) {
            return 0;
        }
        // 遍历到非陆地的地方直接返回0【海洋以及已探索陆地】
        if (grid[r][c] != 1) {
            return 0;
        }
        // 遍历过的陆地设置为2,防止重复计数
        grid[r][c] = 2;

        // 每发现一格岛屿,面积就加1 
        return 1 + area(grid, r, c + 1) +  area(grid, r, c - 1) + area(grid,
                r + 1, c) + area(grid, r - 1, c);
    }

    private boolean isInArea(int[][] grid, int r, int c) {
        // 判断当前坐标是否仍然在岛屿范围内
        return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length;
    }
}

复杂度分析

计算岛屿的最大面积通常也使用深度优先搜索(DFS)或广度优先搜索(BFS)来解决。以下是使用DFS算法来计算岛屿最大面积的时间和空间复杂度分析:

时间复杂度: 在最坏情况下,DFS需要访问矩阵中的每个格子一次,因此时间复杂度仍然是O(MN),其中M是矩阵的行数,N是矩阵的列数。每次访问一个岛屿格子时,需要递归地访问与之相邻的陆地格子,但总体的时间复杂度仍然是O(MN)。

空间复杂度: 空间复杂度取决于递归调用的深度。在最坏情况下,如果整个矩阵都是陆地,DFS的递归深度可能达到MN,因此空间复杂度为O(MN)。通常,DFS的空间复杂度还包括了用于存储访问标记的数据结构(如一个额外的矩阵或集合),因此实际的空间复杂度可能稍微高一些。

与计算岛屿数量类似,如果使用迭代而不是递归来实现DFS,可以通过使用栈来降低空间复杂度,但时间复杂度仍然是O(M*N)。

总结一下,计算岛屿的最大面积问题的时间复杂度是O(MN),空间复杂度通常为O(MN),但在一些优化的情况下可以降低到O(min(M, N))。这仍然取决于具体的实现方式和问题的输入。

岛屿的周长

继续用DFS网络搜索框架解这道题

题干

在这里插入图片描述

解题思路

岛屿的周长是计算岛屿全部的「边缘」,而这些边缘就是我们在 DFS 遍历中,dfs 函数返回的位置。观察题目示例,我们可以将岛屿的周长中的边分为两类,如下图所示。黄色的边是与网格边界相邻的周长,而蓝色的边是与海洋格子相邻的周长
在这里插入图片描述
当我们的 dfs 函数因为「坐标 (r, c) 超出网格范围」返回的时候,实际上就经过了一条黄色的边;而当函数因为「当前格子是海洋格子」返回的时候,实际上就经过了一条蓝色的边。这样,我们就把岛屿的周长跟 DFS 遍历联系起来了

代码实现

给出代码实现基本档案

基本数据结构数组
辅助数据结构
算法搜索算法
技巧

其中数据结构、算法和技巧分别来自:

  • 10 个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树
  • 10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法
  • 技巧:双指针、滑动窗口、中心扩散

当然包括但不限于以上

class Solution {
    public int islandPerimeter(int[][] grid) {
        int perimeter = 0;
        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[0].length; c++) {
                if (grid[r][c] == 1) {
                    perimeter = dfsLength(grid, r, c);
                }
            }
        }
        return perimeter;
    }

    private int dfsLength(int[][] grid, int r, int c) {
        // 1 函数因为「坐标 (r, c) 超出网格范围」返回,对应一条黄色的边
        if (!isInArea(grid, r, c)) {
            return 1;
        }
        // 2 分开讨论非陆地【海洋以及已探索陆地】
        // 2-1 函数因为「当前格子是海洋格子」返回,对应一条蓝色的边
        if (grid[r][c] == 0) {
            return 1;
        }
        // 2-2 函数因为「当前格子是已遍历的陆地格子」返回,和周长没关系
        if (grid[r][c] ==2 ) {
            return 0;
        }
        grid[r][c] = 2;
        // 继续向四面拓展
        return dfsLength(grid, r, c + 1) + dfsLength(grid, r, c - 1) + dfsLength(grid,
                r + 1, c) + dfsLength(grid, r - 1, c);
    }

    private boolean isInArea(int[][] grid, int r, int c) {
        return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length;
    }
}

复杂度分析

计算岛屿的周长通常可以在深度优先搜索(DFS)或广度优先搜索(BFS)的基础上实现。以下是使用DFS算法来计算岛屿周长的时间和空间复杂度分析:

时间复杂度: 在最坏情况下,DFS需要访问矩阵中的每个岛屿格子一次,因此时间复杂度为O(M*N),其中M是矩阵的行数,N是矩阵的列数。对于每个岛屿格子,DFS会探索与之相邻的四个方向,所以在最坏情况下,访问一个岛屿格子的操作的时间复杂度是O(1)。

空间复杂度: 空间复杂度取决于递归调用的深度。在最坏情况下,如果整个矩阵都是陆地,DFS的递归深度可能达到MN,因此空间复杂度为O(MN)。通常,DFS的空间复杂度还包括了用于存储访问标记的数据结构(如一个额外的矩阵或集合),因此实际的空间复杂度可能稍微高一些。

与计算岛屿数量和最大面积不同,计算岛屿周长问题的时间复杂度是O(M*N),因为它只涉及到对每个岛屿格子的一次访问和检查。

需要注意的是,虽然DFS是一种递归算法,但在实际应用中,可以考虑使用迭代的方式来实现,以避免潜在的栈溢出问题。此时,空间复杂度会有所降低。

总结一下,计算岛屿周长问题的时间复杂度是O(MN),空间复杂度通常为O(MN),但在一些优化的情况下可以降低到O(min(M, N))。这取决于具体的实现方式和问题的输入。

拓展知识:DFS在网格中的应用

深度优先搜索(Depth-First Search,DFS)是一种用于图遍历和搜索的算法,它可以应用于各种问题,包括在网格中的问题。在网格中,DFS通常用于解决以下类型的问题:

  1. 迷宫求解:DFS可用于寻找从一个起始点到达目标点的路径。在一个网格迷宫中,你可以使用DFS来探索不同的路径,直到找到通向目标的路径或者确定没有可行的路径。

  2. 岛屿计数:给定一个由陆地和水组成的网格,DFS可以用于计算陆地区域的数量。通过从一个陆地格子开始,DFS可以递归地标记与之相连的所有陆地格子,从而统计出岛屿的数量

  3. 联通分量计算:DFS还可用于计算一个网格中的连通分量数量。连通分量是指由相互连接的格子组成的区域。DFS可以用于标记和计数这些连通分量。

  4. 单词搜索游戏:在字母矩阵中查找给定单词的存在是另一个DFS的应用。DFS可用于从一个字母格子出发,尝试构建单词并逐步扩展搜索路径,直到找到单词或确定不存在。

  5. 图像填充:DFS可以用于图像处理,例如在图像上进行填充操作。你可以从一个起始像素开始,使用DFS来填充相邻像素,直到达到某个条件为止。

在DFS的应用中,关键是选择适当的起始点,并设计好递归函数或迭代算法,以便在网格中进行深度优先搜索。DFS通常需要使用一个数据结构来记录已经访问过的格子,以防止重复访问,通常可以使用一个集合(集合或哈希表)来实现这个目的

需要注意的是,DFS是一种递归算法,可能会导致栈溢出问题,因此在实际应用中,可能需要考虑使用迭代的方式来实现DFS,或者使用递归的时候设置递归深度限制,以避免潜在的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1061146.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多卡片效果悬停效果

效果展示 页面结构 从页面的结构上看&#xff0c;在默认状态下毛玻璃卡片是有层次感的效果叠加在一起&#xff0c;并且鼠标悬停在卡片区域后&#xff0c;卡片整齐排列。 CSS3 知识点 transform 属性的 rotate 值运用content 属性的 attr 值运用 实现页面整体布局 <div …

代码随想录算法训练营第五十七天 | 动态规划 part 15 | 392.判断子序列、115.不同的子序列

目录 392.判断子序列思路代码 115.不同的子序列思路代码 392.判断子序列 Leetcode 思路 dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度为dp[i][j]递推公式&#xff1a; 初始化&#xff1a;为0遍历顺序&#xff…

日常工作报告生成器微信小程序源码 支持日报,周报,月报,年终终结

相信大家上班都会有做工作报告的情况吧 那么这款小程序就是大家的福音了 只要输入你的工作内容或者岗位自动生成你的工作报告 支持报,周报,月报,年终终结 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88391810 源码下载2&#xff1a;评论留言或私信…

JVM篇---第二篇

系列文章目录 文章目录 系列文章目录一、简述一下JVM的内存模型二、说说堆和栈的区别三、什么时候会触发FullGC一、简述一下JVM的内存模型 1.JVM内存模型简介 JVM定义了不同运行时数据区,他们是用来执行应用程序的。某些区域随着JVM启动及销毁,另外一 些区域的数据是线程性独…

自动化测试框架详解

一、什么是自动化测试框架 在了解什么是自动化测试框架之前&#xff0c;先了解一下什么叫框架&#xff1f;框架是整个或部分系统的可重用设计&#xff0c;表现为一组抽象构件及构件实例间交互的方法;另一种定义认为&#xff0c;框架是可被应用开发者定制的应用骨架。前者是从应…

知识图谱-Neo4j使用详解

neo4j应用场景 知识图谱欺诈检测实时推荐引擎反洗钱主数据管理供应链管理增强网络和IT运营管理能力数据谱系身份和访问管理材料清单 图数据库neo4j简介 关系查询&#xff1a;mysql和neo4j性能对比 neo4j的特性和优点&#xff1a; Neo4j-CQL简介 neo4j的Cypher语言是为处理图…

96.qt qml-http之XMLHttpRequest介绍详解使用

在QML中我们可以通过XMLHttpRequest 来实现http/https访问网络接口,接下来我们先来学习XMLHttpRequest类的常用部分、 由于QML的XMLHttpRequest少部分参数是没有的,所以本章来单独讲解下。下章我们来实现旋转请求按钮以及通用的JSON请求模板方法 1.XMLHttpRequest初步使用 …

计算机网络(六):应用层

参考引用 计算机网络微课堂-湖科大教书匠计算机网络&#xff08;第7版&#xff09;-谢希仁 1. 应用层概述 应用层是计算机网络体系结构的最顶层&#xff0c;是设计和建立计算机网络的最终目的&#xff0c;也是计算机网络中发展最快的部分 早期基于文本的应用 (电子邮件、远程登…

Boost程序库完全开发指南:1.1-C++基础知识点梳理

主要整理了N多年前&#xff08;2010年&#xff09;学习C的时候开始总结的知识点&#xff0c;好长时间不写C代码了&#xff0c;现在LLM量化和推理需要重新学习C编程&#xff0c;看来出来混迟早要还的。 1.shared_ptr 解析&#xff1a;shared_ptr是一种计数指针&#xff0c;当引…

【Linux】【网络】工具:httplib 库的安装与简单使用

文章目录 1. 下载 httplib 库2. 从 Win 传输文件到 Linux3. 解压缩 httplib 库1. struct Request 结构体源码展示2. struct Reponse 结构体源码展示3. httplib 库 Server 类4. httplib 库 Client 类5. 搭建简易 server 服务器6. 搭建简易 client 客户端 1. 下载 httplib 库 要求…

结构体和联合体

目录 一.结构体 1.1什么是结构体&#xff1f; 1.2结构的声明 1.3特殊声明 1.4结构的自引用 1.5 结构体变量的定义和初始化 1.6 结构体内存对齐 1.7修改默认对齐数 二.联合体 2.1联合类型的定义 2.2联合的特点 2.3联合大小的计算 一.结构体 1.1什么是结构体&#xf…

【milkv】max98357a驱动添加speaker

文章目录 一、电路1.1 duo音频接口1.2 I2S2连接 二、I2S2介绍2.1 参考cv182x的dts实现2.2 参考cv1835_fpga2.3 cv180x2.4 改动——保留i2s2.5 I2S小结 三、参考资料3.1 文章3.2 手册 四、驱动路径五、添加codec驱动——max98357a5.1 config5.2 dtsi5.3 dai_driver 六、查看plat…

VUE3照本宣科——内置指令与自定义指令及插槽

VUE3照本宣科——内置指令与自定义指令及插槽 前言一、内置指令1.v-text2.v-html3.v-show4.v-if5.v-else6.v-else-if7.v-for8.v-on9.v-bind10.v-model11.v-slot12.v-pre13.v-once14.v-memo15.v-cloak 二、自定义指令三、插槽1.v-slot2.useSlots3.defineSlots() 前言 &#x1f…

Chrome之解决DevTools: Failed to load data:No resource with given identifier found

问题 使用DevTools抓包时候, 有些跨域请求无法在加载出来, 提示 Failed to load data:No resource with given identifier found 解决办法 换其他浏览器 下断点 打开DevTools, 选择源代码/来源/Sources,找到事件监听器断点/Event Listener Breakpoints, 找到加载/Load下面…

C++树详解

树 树的定义 树&#xff08;Tree&#xff09;是n&#xff08;n≥0&#xff09;个结点的有限集。n0时称为空树。在任意一颗非空树中&#xff1a;①有且仅有一个特定的称为根&#xff08;Root&#xff09;的结点&#xff1b;②当n>1时&#xff0c;其余结点可分为m&#xff08…

十天学完基础数据结构-第七天(图(Graph))

图的基本概念 图是一种数据结构&#xff0c;用于表示对象之间的关系。它由两个基本组件构成&#xff1a; 顶点&#xff08;Vertex&#xff09;&#xff1a;也被称为节点&#xff0c;代表图中的对象或实体。 边&#xff08;Edge&#xff09;&#xff1a;连接两个顶点的线&…

【setxattr+userfaultfd】SECCON2020-kstack

这个题主要还是练习 userfaultfd 的利用。说实话&#xff0c;userfaultfd 的利用还是挺多的&#xff0c;虽然在新的内核版本已经做了相关保护。 老规矩&#xff0c;看下启动脚本 #!/bin/sh qemu-system-x86_64 \-m 128M \-kernel ./bzImage \-initrd ./rootfs.cpio \-append …

第三章、运输层

文章目录 3.1 概述和运输层服务3.1.1 运输层和网络层的关系3.1.2 因特网运输层概述 3.2 多路复用与多路分解3.3 无连接运输&#xff1a;UDP3.4 可靠数据传输原理3.4.1构造可靠数据传输协议rdt1.0rdt2.xrdt3.0 3.4.2 流水线可靠数据传输协议3.4.3 回退N步3.4.4选择重传 3.5 面向…

x64内核实验1-调试环境配置

x64内核实验1-调试环境配置 这是一套x64内核实验的课程&#xff0c;我之前学习32位内核的时候就是在网上找的各种教程当学完32位很久之后发现在网上的64位内核相关的完整教程真的很少&#xff0c;所以就想着不如自己写一点方便对内核有兴趣的人能更好的入门&#xff0c;首先声…

哈希原理和解决哈希冲突方法

第一 哈希介绍 哈希和红黑树是我早期就听过的名词&#xff0c;却一直没见到真面目&#xff0c;实现哈希后才发现原来我早就使用过了哈希。看下面例题。 用map和set都可以轻松解决&#xff0c;但是在我写这题时我还不会用map和set&#xff0c;我用了另一种方法。看下面代码。先定…