算法|图论 4

2023-09-15 14:49:16

LeetCode 827.最大人工岛

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述:给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。

返回执行此操作后,grid 中最大的岛屿面积是多少?

岛屿 由一组上、下、左、右四个方向相连的 1 形成。

解题思路(深度优先遍历):

首先,通过深度优先遍历,将所有岛屿,按片为单位全部都标记下来,也就是同一片岛屿的编号相同,不同岛屿的编号不同。我们用unordered_map记录下来这一片片岛屿的面积。

下一步,直接通过遍历所有的海洋也就是标号为0的点,去看其四周的岛屿能不能链接起来,如果可以,我们就将对应岛屿的编号添加到unordered_set中去,并将对应的岛屿值相加到count中,再和result对比,取最大值即可。

class Solution {
public:
    int count;//count用来记录当前这片岛屿的面积
    int dir[4][2] = {0,1,1,0,-1,0,0,-1};
    //mark标记岛屿编号
    void dfs(vector<vector<int>> &grid,vector<vector<bool>> &visited,int x,int y,int mark){
        if(visited[x][y] || grid[x][y] == 0) return;
        visited[x][y] = true;
        grid[x][y] = mark;//标记岛屿标号
        count++;//当前岛屿面积加一
        for(int i=0;i<4;i++){
            int nextx = dir[i][0] + x;
            int nexty = dir[i][1] + y;
            if(nextx < 0 || nexty < 0 || nextx >= grid.size() || nexty >= grid[0].size())continue;
            dfs(grid,visited,nextx,nexty,mark);
        }
    }
    int largestIsland(vector<vector<int>>& grid) {
        int n = grid.size(),m = grid[0].size();
        vector<vector<bool>> visited = vector<vector<bool>> (n,vector<bool>(m,false));
        
        //记录岛屿编号对应的岛屿面积,key是岛屿的标号,value是这片岛屿的面积。
        //一片岛屿的标号都是一样的
        unordered_map<int,int> gridNum;
        int mark = 2;//标号从2开始
        bool isAllGrid = true;//标记是否全是岛屿,全是岛屿我们直接返回m*n即可
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(grid[i][j] == 0) isAllGrid = false;//不全是岛屿
                if(!visited[i][j] && grid[i][j] == 1){
                    count = 0;//清空count,防止多次记录同一片岛屿
                    dfs(grid,visited,i,j,mark);
                    gridNum[mark] = count;//将对应的键值对存储进map
                    mark++;//标号自增,防止标号重复
                }
            }
        }
    	if (isAllGrid) return n * m; //全是岛屿直接返回
      int result = 0; // 记录最后结果
        unordered_set<int> visitedGrid; // 标记这次的0链接过的岛屿
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int count = 1; // 记录连接之后的岛屿数量
                visitedGrid.clear(); // 每次使用时清空。
                if (grid[i][j] == 0) {
                    for (int k = 0; k < 4; k++) {
                        int neari = i + dir[k][1]; // 计算相邻坐标
                        int nearj = j + dir[k][0];
                        if (neari < 0 || neari >= grid.size() || nearj < 0 || nearj >= grid[0].size()) continue;
                        
                        //count是计数,看这个岛屿对应的mark(标记)有没有被添加进来,
                        //没有则代表这片岛屿没有被链接过。因为只要链接我们就去取其中这片岛屿
                        //的值,只要有一个链接了,别的全都不能再链接了。
                        if (visitedGrid.count(grid[neari][nearj])) continue; // 添加过的岛屿不要重复添加
                        // 把相邻四面的岛屿数量加起来
                        count += gridNum[grid[neari][nearj]];
                        visitedGrid.insert(grid[neari][nearj]); // 标记该岛屿已经添加过
                    }
                }
                result = max(result, count);
            }
        }
        return result;
    }
};

总结:

  • 深搜和广搜的问题,广搜里面写的那个思路很清奇,还是得多看题目的提示,可以减少一点时间和空间的损耗。

LeetCode 127- 单词接龙

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述:字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk:

  • 每一对相邻的单词只差一个字母。
  • 对于 1 <= i <= k 时,每个 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。
  • sk == endWord

给你两个单词 beginWord 和 endWord 和一个字典 wordList ,返回 beginWordendWord最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0 。

解题思路

首先明确本题题意,意思就是我们需要从字典中找到begin 到 end 的最短路径,每次只能更换一个字母。

本题思路是广度优先遍历,首先我们将begin和step=1入队,并不断取出队首元素,将队首元素中每个字母都进行从'a' - 'z' 的替换。如果能在set中找到替换后的元素,说明可以走这一步,我们就将其入队,并且将set中对应的元素删除,防止出现反复走这一步的情况。并且替换一个字母后,我们再将其还原看替换其他字母能不能行。直到遇到队首元素为end的情况,直接返回step即可。

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        //开始我们将所有单词都记录到set中,s用来记录字典中的单词是否已经用过,用过则直接删除
        unordered_set<string> s;
        //符号 & 表明 i 是一个引用变量,能让接下来的循环可以修改s中的内容
        for(auto &i : wordList)s.insert(i);
        
    	//队列q用来表示当前到达当前字符需要的步数
        queue<pair<string,int>> q;
        //压入开始词和1
        q.push({beginWord,1});

        //tmp为每次我们要换的单词
        string tmp;
        //step为每次的步数
        int step;
        
        while(!q.empty()){
            //若队头元素就是最终单词,则直接返回对应的步数
            if(q.front().first == endWord){
                return (q.front().second);
            }

            //取出队头元素
            tmp = q.front().first;
            step = q.front().second;
            q.pop();

            //开始尝试,ch表示当前取出来字符串的每个字符。
            char ch;
            //这里是将当前字符串的每个字符都试试看看替换成a-z中的字符能否在字典中找到。
            //能找到我们就入队,并且还原,因为每次只修改一个字符,如果不能,则直接还原。
            for(int i=0;i<tmp.length();i++){
                ch = tmp[i];
                for(char c='a';c<='z';c++){
                    if(ch == c) continue;
                    tmp[i] = c;
                    if(s.find(tmp) != s.end()){
                        q.push({tmp,step+1});
                        s.erase(tmp);
                    }
                    tmp[i] = ch;
                }
            }
        }
        return 0;
    }
};

总结:

  • 广度优先,但不知道如何模拟广度,原来就是替换字母。还是多练习,多看思路才行。
更多推荐

理解MySQL的会话变量、局部变量和全局变量

理解MySQL的会话变量、局部变量和全局变量1.MySQL变量分类根据作用范围不同,分为会话用户变量和局部变量。会话用户变量:作用域和会话变量一样,只对当前连接会话有效。局部变量:只在BEGIN和END语句块中有效,局部变量只能在存储过程和存储函数中使用。全局变量:在MySQL服务器启动运行后,系统内置变量。2.变量定

QRunnable与外界互传对象

1.概述QRunnable与外界互通讯是有两种方法的使用多继承。让我们的自定义线程类同时继承于QRunnable和QObject,这样就可以使用信号和槽,但是多线程使用比较麻烦,特别是继承于自定义的类时,容易出现接口混乱,所以在项目中尽量少用多继承。//使用多继承classrunnable:publicQObject,

xdebug3开启profile和trace

【xdebug开启profiler】https://xdebug.org/docs/profilerhttp://www.xdebug.org.cn/docs/profiler1、php.ini添加下面配置然后重启php容器:xdebug.mode=profile;这个目录保存profile和trace文件xdebug

TQ210-Bootloader-Uboot(LTS)

Bootloader的作用Bootloader是位于计算机系统启动过程中的程序,它的主要作用是将操作系统从磁盘等外部存储介质加载到计算机内存中,并启动操作系统执行。Bootloader通常包括硬件初始化、自检、异常处理和启动操作系统等功能。它是计算机系统中非常重要的部分,直接影响系统启动和运行的稳定性和性能。U-boo

10分钟设置免费海外远程桌面

前言本教程将向您介绍如何使用AmazonLightsail服务的免费套餐轻松搭建属于您的远程桌面。依托于Amazon全球可用区,您可以在世界各地搭建符合您配置需求的远程桌面。本教程需要先拥有亚马逊云科技海外账户。现在注册亚马逊云科技账户可以享受12个月免费套餐,包括EC2等多种热门产品。亚马逊云科技开发者社区为开发者们

LinkedList与链表

目录一、Arraylist的缺陷二、链表2.1链表的概念和结构2.2链表的实现三、链表面试题3.1删除链表中所有值为val的节点3.2反转一个单链表3.3链表的中间节点3.4将有序链表合并3.5输出倒数第k个节点3.6链表分割3.7链表的回文结构3.8找两个链表的公共节点3.9判断链表是否有环3.10找链表入环的第一个

Axure设计之数据图表折线图(中继器)

折线图是一种用于显示数据随时间变化或有序类别关系变化的图形。在折线图中,数据点用线段连接,并按照时间顺序或类别顺序排列。通过观察折线图的走势和变化,可以获得数据变化的趋势和规律。在系统统计分析中折线图经常被使用的数据图表。一、效果展示1、该示例为折线图,分别对客流量和购买量以月份为单位进行统计;2、横轴为统计月份,纵轴

Python经典练习题(一)

文章目录🍀第一题🍀第二题🍀第三题🍀第四题🍀第五题🍀第一题有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?这里我们使用两种方法进行求解解法一:循环套循环count=0foriinrange(1,5):forjinrange(1,5):forkinrange(1,5):if(i!

如何辨认是否是高防服务器?

因为现在高防服务器比较出名,很多IDC服务器商都标榜自己的服务器是高防服务器,那我们怎么辨别服务器商说的高防服务器是否是真正的高防服务器呢?今天小编就告诉大家几点辨认是否是高防服务器的小要点。向选择好的服务器商要一下高防服务器的IP,然后通过简单的测试来看一看,也就是ping指令(用来测试网络连接是否正常)来检查,一般

如何使用插件扩展Vue的功能

Vue是一款流行的前端JavaScript框架,它的核心库提供了许多强大的功能,但有时我们需要额外的功能来满足特定需求。这时,使用插件来扩展Vue的功能是一个很好的选择。本文将详细介绍如何使用插件来扩展Vue的功能,包括创建、注册和使用插件。Vue提供了强大的插件系统,供大家来扩展项目功能。开发者可以自由的使用公开的第

Python+pytest接口自动化之参数关联

一、什么是参数关联?参数关联,也叫接口关联,即接口之间存在参数的联系或依赖。在完成某一功能业务时,有时需要按顺序请求多个接口,此时在某些接口之间可能会存在关联关系。比如:B接口的某个或某些请求参数是通过调用A接口获取的,即需要先请求A接口,从A接口的返回数据中拿到需要的字段值,在请求B接口时作为请求参数传入。二、有哪些

热文推荐