面试经典150题——图

文章目录

  • 1、岛屿数量
    • 1.1 题目链接
    • 1.2 题目描述
    • 1.3 解题代码
    • 1.4 解题思路
  • 2、被围绕的区域
    • 2.1 题目链接
    • 2.2 题目描述
    • 2.3 解题代码
    • 2.4 解题思路
  • 3、克隆图
    • 3.1 题目链接
    • 3.2 题目描述
    • 3.3 解题代码
    • 3.4 解题思路
  • 4、除法求值
    • 4.1 题目链接
    • 4.2 题目描述
    • 4.3 解题代码
    • 4.4 解题思路
  • 5、课程表
    • 5.1 题目链接
    • 5.2 题目描述
    • 5.3 解题代码
    • 5.4 解题思路
  • 6、课程表 II
    • 6.1 题目链接
    • 6.2 题目描述
    • 6.3 解题代码
    • 6.4 解题思路


1、岛屿数量

1.1 题目链接

点击跳转到题目位置

1.2 题目描述

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 300
  • grid[i][j] 的值为 ‘0’ 或 ‘1’

1.3 解题代码

class Solution {
    int[][] dir = {
        {-1, 0},
        {1, 0},
        {0, 1},
        {0, -1},
    };

    public int numIslands(char[][] grid) {
        Map<Integer, Integer> hash = new HashMap<Integer, Integer>(); 
        int m = grid.length;
        int n = grid[0].length;
        int ret = 0;
        Queue<Integer> q = new LinkedList();
        for(int i = 0; i < m; ++i){
            for(int j = 0; j < n; ++j){
                if(grid[i][j] == '1' && !hash.containsKey(500 * i + j)){
                    q.offer(500 * i + j);
                    hash.put(500 * i + j, 1);
                    ++ret;
                }
                while(!q.isEmpty()){
                    int num = q.peek();
                    q.poll();
                    int x = num / 500;
                    int y = num % 500;
                    for(int k = 0; k < 4; ++k){
                        int tx = x + dir[k][0];
                        int ty = y + dir[k][1];
                        if(tx < 0 || tx >= m || ty < 0 || ty >= n || grid[tx][ty] == '0'){
                            continue;
                        }
                        if(!hash.containsKey(tx * 500 + ty)){
                            hash.put(tx * 500 + ty, 1);
                            q.offer(tx * 500 + ty);
                        }
                    }
                }
            }
        }
        return ret;
    }
}

1.4 解题思路

  1. 使用广度优先搜索来解决问题。
  2. 广度优先搜索的核心思路为哈希+队列

2、被围绕的区域

2.1 题目链接

点击跳转到题目位置

2.2 题目描述

给你一个 m x n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ 组成,捕获 所有 被围绕的区域:

  • **连接:**一个单元格与水平或垂直方向上相邻的单元格连接。
  • 区域:连接所有 ‘O’ 的单元格来形成一个区域。
  • **围绕:**如果您可以用 ‘X’ 单元格 连接这个区域,并且区域中没有任何单元格位于 board 边缘,则该区域被 ‘X’ 单元格围绕。

通过 原地 将输入矩阵中的所有 ‘O’ 替换为 ‘X’ 来 捕获被围绕的区域。你不需要返回任何值。

提示:

  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 200
  • board[i][j] 为 ‘X’ 或 ‘O’

2.3 解题代码

class Solution {
    int[][] dir = {
        {-1, 0},
        {1, 0},
        {0, -1},
        {0, 1},
    };
    Map<Integer, Integer> hash = new HashMap<Integer, Integer>();

    void bfs(char[][] board, int startX, int startY, int m, int n){
        Queue<Integer> q = new LinkedList();
        q.offer(startX * 500 + startY);
        hash.put(startX * 500 + startY, 1);
        while(!q.isEmpty()){
            int num = q.peek();
            q.poll();
            int x = num / 500;
            int y = num % 500;
            for(int k = 0; k < 4; ++k){
                int tx = x + dir[k][0];
                int ty = y + dir[k][1];
                if(tx < 0 || tx >= m || ty < 0 || ty >= n || board[tx][ty] == 'X'){
                    continue;
                }
                if(!hash.containsKey(tx * 500 + ty)){
                    hash.put(tx * 500 + ty, 1);
                    q.offer(tx * 500 + ty);
                }
            }
        }
    }

    public void solve(char[][] board) {
        
        int m = board.length;
        int n = board[0].length;
        for(int i = 0; i < m; ++i){
            if(board[i][0] == 'O' && !hash.containsKey(i * 500 + 0)){
                bfs(board, i, 0, m, n);
            }
            if(board[i][n - 1] == 'O' && !hash.containsKey(i * 500 + n - 1)){
                bfs(board, i, n - 1, m, n);
            }
        }
        for(int j = 0; j < n; ++j){
            if(board[0][j] == 'O' && !hash.containsKey(0 * 500 + j)){
                bfs(board, 0, j, m, n);
            }
            if(board[m - 1][j] == 'O' && !hash.containsKey((m - 1) * 500 + j)){
                bfs(board, m - 1, j, m, n);
            }
        }

        for(int i = 0; i < m; ++i){
            for(int j = 0; j < n; ++j){
                if(board[i][j] == 'O' && !hash.containsKey(i * 500 + j)){
                    board[i][j] = 'X';
                }
            }
        }
    }
}

2.4 解题思路

  1. 广度优先搜索,首先先从地图边缘开始进行广搜,将所有与地图边缘连接且字符为’O’的点用哈希表标注起来
  2. 之后遍历地图,对所有字符为‘O’,并且哈希表中不存在的点转化成‘X’。

3、克隆图

3.1 题目链接

点击跳转到题目位置

3.2 题目描述

给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。

图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])
在这里插入图片描述
测试用例格式:

简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1(val = 1),第二个节点值为 2(val = 2),以此类推。该图在测试用例中使用邻接列表表示。

邻接列表 是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。

给定节点将始终是图中的第一个节点(值为 1)。你必须将 给定节点的拷贝 作为对克隆图的引用返回。

提示:

  • 这张图中的节点数在 [0, 100] 之间。
  • 1 <= Node.val <= 100
  • 每个节点值 Node.val 都是唯一的,
  • 图中没有重复的边,也没有自环。
  • 图是连通图,你可以从给定节点访问到所有节点。

3.3 解题代码

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> neighbors;
    public Node() {
        val = 0;
        neighbors = new ArrayList<Node>();
    }
    public Node(int _val) {
        val = _val;
        neighbors = new ArrayList<Node>();
    }
    public Node(int _val, ArrayList<Node> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
}
*/

class Solution {
    Map<Node, Node> hash = new HashMap<Node, Node>();

    public Node cloneGraph(Node node) {
        if(node == null){
            return null;
        }
        if(!hash.containsKey(node)){
            Node newNode = new Node(node.val);
            hash.put(node, newNode);
            for(int i = 0; i < node.neighbors.size(); ++i){
                newNode.neighbors.add(cloneGraph(node.neighbors.get(i)));
            }
        }
        return hash.get(node);
    }
}

3.4 解题思路

  1. 递归求解即可,题目与之前的138. 随机链表的复制一致。

4、除法求值

4.1 题目链接

点击跳转到题目位置

4.2 题目描述

给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。

另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。

返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。

**注意:**输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。

**注意:**未在等式列表中出现的变量是未定义的,因此无法确定它们的答案。

提示:

  • 1 <= equations.length <= 20
  • equations[i].length == 2
  • 1 <= Ai.length, Bi.length <= 5
  • values.length == equations.length
  • 0.0 < values[i] <= 20.0
  • 1 <= queries.length <= 20
  • queries[i].length == 2
  • 1 <= Cj.length, Dj.length <= 5
  • Ai, Bi, Cj, Dj 由小写英文字母与数字组成

4.3 解题代码

class Solution {
    Map<String, Integer> hash = new HashMap<String, Integer>();

    int find(List<Integer> pre, List<Double> weight, int x){
        
        if(x != pre.get(x)){
            int origin = pre.get(x);
            pre.set(x, find(pre, weight, pre.get(x))); 
            weight.set(x, weight.get(x) * weight.get(origin));
        }

        return pre.get(x);
    }

    void union(List<Integer> pre, List<Double> weight, double value, int x, int y){
        int index1 = find(pre, weight, x);
        int index2 = find(pre, weight, y);
        if(index1 != index2){
            pre.set(index1, index2);
            weight.set(index1, weight.get(y) * value / weight.get(x)); 
        }
        
    }
    
    public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {

        int equationsSize = equations.size();
        int queriesSize = queries.size();
        
        double[] res = new double[queriesSize];

        int id = 0;
        List<Integer> pre = new ArrayList<>();
        List<Double> weight = new ArrayList<Double>();
        for(int i = 0; i < equationsSize; ++i){
            String str1 = equations.get(i).get(0);
            String str2 = equations.get(i).get(1);
            if(!hash.containsKey(str1)){
                hash.put(str1, id);
                pre.add(id);
                weight.add(1.0d);
                id++;        
            }

            if(!hash.containsKey(str2)){
                hash.put(str2, id);
                pre.add(id);
                weight.add(1.0);
                id++;
            }
            union(pre, weight, values[i], hash.get(str1), hash.get(str2));
        }

        for(int i = 0; i < queriesSize; ++i){
            String str1 = queries.get(i).get(0);
            String str2 = queries.get(i).get(1);

            if(!hash.containsKey(str1) || !hash.containsKey(str2)){
                res[i] = -1.0;
                continue;
            }

            Integer id1 = hash.get(str1);
            Integer id2 = hash.get(str2);
            if(find(pre, weight, id1) != find(pre, weight, id2)){
                res[i] = -1.0d;
                continue;
            }

            double value1 = weight.get(id1);
            double value2 = weight.get(id2);
            res[i] = value1 / value2;
        }
        
        return res;
    }
}

4.4 解题思路

  1. 使用并查集解决问题。

5、课程表

5.1 题目链接

点击跳转到题目位置

5.2 题目描述

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai必须 先学习课程 bi

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

提示:

  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= 5000
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • prerequisites[i] 中的所有课程对 互不相同

5.3 解题代码

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<List<Integer>> edge = new ArrayList<>();
        for (int i = 0; i < numCourses; ++i) {
            edge.add(new ArrayList<>());
        }
        int[] deg = new int[numCourses];
        int n = prerequisites.length;
        for(int i = 0; i < n; ++i){
            int x = prerequisites[i][0];
            int y = prerequisites[i][1];
            deg[x]++;
            edge.get(y).add(x);
        }
        Queue<Integer> q = new LinkedList<Integer>();

        for(int i = 0; i < numCourses; ++i){
            if(deg[i] == 0){
                q.offer(i);
            }
        }
        
        while(!q.isEmpty()){
            int x = q.peek();
            q.poll();
            numCourses--;
            for(int i = 0; i < edge.get(x).size(); ++i){
                int num = edge.get(x).get(i);
                deg[num]--;
                if(deg[num] == 0){
                    q.offer(num);
                }
            }
        }
        return numCourses == 0;
    }
}

5.4 解题思路

  1. 使用拓扑排序来解决问题
  2. 每次将度为0的结点放入队列中,每次从队首取点,并且numCourses–。如果最后图中存在环的话,则numCourses则不为0。

6、课程表 II

6.1 题目链接

点击跳转到题目位置

6.2 题目描述

现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai必须 先选修 bi

  • 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。

返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组

提示:

  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= numCourses * (numCourses - 1)
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • ai != bi
    所有[ai, bi] 互不相同

6.3 解题代码

class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        int[] res = new int[numCourses];
        int k = 0;
        List<List<Integer>> edge = new ArrayList<>();
        for (int i = 0; i < numCourses; ++i) {
            edge.add(new ArrayList<>());
        }
        int[] deg = new int[numCourses];
        int n = prerequisites.length;
        for(int i = 0; i < n; ++i){
            int x = prerequisites[i][0];
            int y = prerequisites[i][1];
            deg[x]++;
            edge.get(y).add(x);
        }
        Queue<Integer> q = new LinkedList<Integer>();

        for(int i = 0; i < numCourses; ++i){
            if(deg[i] == 0){
                q.offer(i);
            }
        }
        
        while(!q.isEmpty()){
            int x = q.peek();
            res[k++] = x;
            q.poll();
            numCourses--;
            for(int i = 0; i < edge.get(x).size(); ++i){
                int num = edge.get(x).get(i);
                deg[num]--;
                if(deg[num] == 0){
                    q.offer(num);
                }
            }
        }
        if(numCourses == 0){
            return res;
        }
        return new int[0];
    }
}

6.4 解题思路

  1. 使用拓扑排序解题
  2. 与上一题的区别就是需要把每次队首的元素放入结果数组中,最后符合条件的输出结果数组,否则输出空数组。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot电脑组装系统平台系统功能实现六

一、前言介绍&#xff1a; 1.1 项目摘要 随着科技的进步&#xff0c;计算机硬件技术日新月异&#xff0c;包括处理器&#xff08;CPU&#xff09;、主板、内存、显卡等关键部件的性能不断提升&#xff0c;为电脑组装提供了更多的选择和可能性。不同的硬件组合可以构建出不同类…

万字长文总结前端开发知识---JavaScriptVue3Axios

JavaScript学习目录 一、JavaScript1. 引入方式1.1 内部脚本 (Inline Script)1.2 外部脚本 (External Script) 2. 基础语法2.1 声明变量2.2 声明常量2.3 输出信息 3. 数据类型3.1 基本数据类型3.2 模板字符串 4. 函数4.1 具名函数 (Named Function)4.2 匿名函数 (Anonymous Fun…

MySQL(单表访问)

今天是新年&#xff0c;祝大家新年快乐&#xff0c;但是生活还是得继续。 后面也会持续更新&#xff0c;学到新东西会在其中补充。 建议按顺序食用&#xff0c;欢迎批评或者交流&#xff01; 缺什么东西欢迎评论&#xff01;我都会及时修改的&#xff01; 大部分截图和文章采…

HarmonyOS简介:应用开发的机遇、挑战和趋势

问题 更多的智能设备并没有带来更好的全场景体验 连接步骤复杂数据难以互通生态无法共享能力难以协同 主要挑战 针对不同设备上的不同操作系统&#xff0c;重复开发&#xff0c;维护多套版本 多种语言栈&#xff0c;对人员技能要求高 多种开发框架&#xff0c;不同的编程…

【Elasticsearch】Elasticsearch的查询

Elasticsearch的查询 DSL查询基础语句叶子查询全文检索查询matchmulti_match 精确查询termrange 复合查询算分函数查询bool查询 排序分页基础分页深度分页 高亮高亮原理实现高亮 RestClient查询基础查询叶子查询复合查询排序和分页高亮 数据聚合DSL实现聚合Bucket聚合带条件聚合…

使用 KNN 搜索和 CLIP 嵌入构建多模态图像检索系统

作者&#xff1a;来自 Elastic James Gallagher 了解如何使用 Roboflow Inference 和 Elasticsearch 构建强大的语义图像搜索引擎。 在本指南中&#xff0c;我们将介绍如何使用 Elasticsearch 中的 KNN 聚类和使用计算机视觉推理服务器 Roboflow Inference 计算的 CLIP 嵌入构建…

LogicFlow 一款流程图编辑框架

LogicFlow是什么 LogicFlow是一款流程图编辑框架&#xff0c;提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。LogicFlow支持前端自定义开发各种逻辑编排场景&#xff0c;如流程图、ER图、BPMN流程等。在工作审批流配置、机器人逻辑编排、无代码…

几种K8s运维管理平台对比说明

目录 深入体验**结论**对比分析表格**1. 功能对比****2. 用户界面****3. 多租户支持****4. DevOps支持** 细对比分析1. **Kuboard**2. **xkube**3. **KubeSphere**4. **Dashboard****对比总结** 深入体验 KuboardxkubeKubeSphereDashboard 结论 如果您需要一个功能全面且适合…

《HelloGitHub》第 106 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

R语言学习笔记之高效数据操作

一、概要 数据操作是R语言的一大优势&#xff0c;用户可以利用基本包或者拓展包在R语言中进行复杂的数据操作&#xff0c;包括排序、更新、分组汇总等。R数据操作包&#xff1a;data.table和tidyfst两个扩展包。 data.table是当前R中处理数据最快的工具&#xff0c;可以实现快…

【微服务与分布式实践】探索 Dubbo

核心组件 服务注册与发现原理 服务提供者启动时&#xff0c;会将其服务信息&#xff08;如服务名、版本、所在节点的网络地址等&#xff09;注册到注册中心。服务消费者则可以从注册中心发现可用的服务提供者列表&#xff0c;并与之通信。注册中心会存储服务的信息&#xff0c…

SQL Server查询计划操作符(7.3)——查询计划相关操作符(5)

7.3. 查询计划相关操作符 38)Flow Distinct:该操作符扫描其输入并对其去重。该操作符从其输入得到每行数据时即将其返回(除非其为重复数据行,此时,该数据行会被抛弃),而Distinct操作符在产生任何输出前将消费所有输入。该操作符为逻辑操作符。该操作符具体如图7.2-38中…

【AI】【本地部署】OpenWebUI的升级并移植旧有用户信息

【背景】 OpenWebUI的版本升级频率很高&#xff0c;并会修改旧版本的Bug&#xff0c;不过对于已经在使用的系统&#xff0c;升级后现有用户信息都会丢失&#xff0c;于是研究如何在升级后将现有的用户信息移植到升级后版本。 【准备工作】 OpenWebUI的升级步骤在Docker中有现…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.19 排序革命:argsort的十大高阶用法

1.19 排序革命&#xff1a;argsort的十大高阶用法 目录 #mermaid-svg-Qu8PcmLkIc1pOQJ7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Qu8PcmLkIc1pOQJ7 .error-icon{fill:#552222;}#mermaid-svg-Qu8PcmLkIc1pOQJ…

分布式数据库应用实践:架构设计与性能优化

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 引言 在当今数据驱动的世界中&#xff0c;分布式数据库因其高可用性、可扩展性和强大的容错能力&#xff0c;已成为现代企业存储…

实战纪实 | 真实HW漏洞流量告警分析

视频教程在我主页简介和专栏里 目录&#xff1a; 一、web.xml 文件泄露 二、Fastjson 远程代码执行漏洞 三、hydra工具爆破 四、绕过验证&#xff0c;SQL攻击成功 五、Struts2代码执行 今年七月&#xff0c;我去到了北京某大厂参加HW行动&#xff0c;因为是重点领域—-jr&…

一组开源、免费、Metro风格的 WPF UI 控件库

前言 今天大姚给大家分享一个开源、免费、Metro风格的 WPF UI 控件库&#xff1a;MahApps.Metro。 项目介绍 MahApps.Metro 是一个开源、免费、Metro风格的 WPF UI 控件库&#xff0c;提供了现代化、平滑和美观的控件和样式&#xff0c;帮助开发人员轻松创建具有现代感的 Win…

12 款开源OCR发 PDF 识别框架

2024 年 12 款开源文档解析框架的选型对比评测&#xff1a;PDF解析、OCR识别功能解读、应用场景分析及优缺点比较 这是该系列的第二篇文章&#xff0c;聚焦于智能文档处理&#xff08;特别是 PDF 解析&#xff09;。无论是在模型预训练的数据收集阶段&#xff0c;还是基于 RAG…

【MySQL】--- 复合查询 内外连接

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; MySQL &#x1f3e0; 基本查询回顾 假设有以下表结构&#xff1a; 查询工资高于500或岗位为MANAGER的雇员&#xff0c;同时还要满足他们的姓名首字母为…

jemalloc 5.3.0的tsd模块的源码分析

一、背景 在主流的内存库里&#xff0c;jemalloc作为android 5.0-android 10.0的默认分配器肯定占用了非常重要的一席之地。jemalloc的低版本和高版本之间的差异特别大&#xff0c;低版本的诸多网上整理的总结&#xff0c;无论是在概念上和还是在结构体命名上在新版本中很多都…