• 算法|图论 4


    LeetCode 827.最大人工岛

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

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

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

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

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

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

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

    1. class Solution {
    2. public:
    3. int count;//count用来记录当前这片岛屿的面积
    4. int dir[4][2] = {0,1,1,0,-1,0,0,-1};
    5. //mark标记岛屿编号
    6. void dfs(vector<vector<int>> &grid,vector> &visited,int x,int y,int mark){
    7. if(visited[x][y] || grid[x][y] == 0) return;
    8. visited[x][y] = true;
    9. grid[x][y] = mark;//标记岛屿标号
    10. count++;//当前岛屿面积加一
    11. for(int i=0;i<4;i++){
    12. int nextx = dir[i][0] + x;
    13. int nexty = dir[i][1] + y;
    14. if(nextx < 0 || nexty < 0 || nextx >= grid.size() || nexty >= grid[0].size())continue;
    15. dfs(grid,visited,nextx,nexty,mark);
    16. }
    17. }
    18. int largestIsland(vector<vector<int>>& grid) {
    19. int n = grid.size(),m = grid[0].size();
    20. vector<vector<bool>> visited = vector> (n,vector(m,false));
    21. //记录岛屿编号对应的岛屿面积,key是岛屿的标号,value是这片岛屿的面积。
    22. //一片岛屿的标号都是一样的
    23. unordered_map<int,int> gridNum;
    24. int mark = 2;//标号从2开始
    25. bool isAllGrid = true;//标记是否全是岛屿,全是岛屿我们直接返回m*n即可
    26. for(int i=0;i<n;i++){
    27. for(int j=0;j<m;j++){
    28. if(grid[i][j] == 0) isAllGrid = false;//不全是岛屿
    29. if(!visited[i][j] && grid[i][j] == 1){
    30. count = 0;//清空count,防止多次记录同一片岛屿
    31. dfs(grid,visited,i,j,mark);
    32. gridNum[mark] = count;//将对应的键值对存储进map
    33. mark++;//标号自增,防止标号重复
    34. }
    35. }
    36. }
    37. if (isAllGrid) return n * m; //全是岛屿直接返回
    38. int result = 0; // 记录最后结果
    39. unordered_set<int> visitedGrid; // 标记这次的0链接过的岛屿
    40. for (int i = 0; i < n; i++) {
    41. for (int j = 0; j < m; j++) {
    42. int count = 1; // 记录连接之后的岛屿数量
    43. visitedGrid.clear(); // 每次使用时清空。
    44. if (grid[i][j] == 0) {
    45. for (int k = 0; k < 4; k++) {
    46. int neari = i + dir[k][1]; // 计算相邻坐标
    47. int nearj = j + dir[k][0];
    48. if (neari < 0 || neari >= grid.size() || nearj < 0 || nearj >= grid[0].size()) continue;
    49. //count是计数,看这个岛屿对应的mark(标记)有没有被添加进来,
    50. //没有则代表这片岛屿没有被链接过。因为只要链接我们就去取其中这片岛屿
    51. //的值,只要有一个链接了,别的全都不能再链接了。
    52. if (visitedGrid.count(grid[neari][nearj])) continue; // 添加过的岛屿不要重复添加
    53. // 把相邻四面的岛屿数量加起来
    54. count += gridNum[grid[neari][nearj]];
    55. visitedGrid.insert(grid[neari][nearj]); // 标记该岛屿已经添加过
    56. }
    57. }
    58. result = max(result, count);
    59. }
    60. }
    61. return result;
    62. }
    63. };

    总结:

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

    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即可。

    1. class Solution {
    2. public:
    3. int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
    4. //开始我们将所有单词都记录到set中,s用来记录字典中的单词是否已经用过,用过则直接删除
    5. unordered_set<string> s;
    6. //符号 & 表明 i 是一个引用变量,能让接下来的循环可以修改s中的内容
    7. for(auto &i : wordList)s.insert(i);
    8. //队列q用来表示当前到达当前字符需要的步数
    9. queue<pair<string,int>> q;
    10. //压入开始词和1
    11. q.push({beginWord,1});
    12. //tmp为每次我们要换的单词
    13. string tmp;
    14. //step为每次的步数
    15. int step;
    16. while(!q.empty()){
    17. //若队头元素就是最终单词,则直接返回对应的步数
    18. if(q.front().first == endWord){
    19. return (q.front().second);
    20. }
    21. //取出队头元素
    22. tmp = q.front().first;
    23. step = q.front().second;
    24. q.pop();
    25. //开始尝试,ch表示当前取出来字符串的每个字符。
    26. char ch;
    27. //这里是将当前字符串的每个字符都试试看看替换成a-z中的字符能否在字典中找到。
    28. //能找到我们就入队,并且还原,因为每次只修改一个字符,如果不能,则直接还原。
    29. for(int i=0;i<tmp.length();i++){
    30. ch = tmp[i];
    31. for(char c='a';c<='z';c++){
    32. if(ch == c) continue;
    33. tmp[i] = c;
    34. if(s.find(tmp) != s.end()){
    35. q.push({tmp,step+1});
    36. s.erase(tmp);
    37. }
    38. tmp[i] = ch;
    39. }
    40. }
    41. }
    42. return 0;
    43. }
    44. };

    总结:

    • 广度优先,但不知道如何模拟广度,原来就是替换字母。还是多练习,多看思路才行。
  • 相关阅读:
    Java基础: java中的四种引用
    C++指针解读(6)-- 指针和字符串
    三款经典的轮式/轮足机器人讲解,以及学习EG2133产生A/B/C驱动电机。个人机器人学习和开发路线(推荐)
    [含毕业设计论文+PPT+源码等]ssm的房屋交易平台+Java后台管理系统|前后分离VUE
    springboot+springsecurity+elementui博客系统-dsblog
    LLM - 大语言模型 基于人类反馈的强化学习(RLHF)
    Python基础学习
    阿里巴巴数字商业知识图谱的构建及应用
    2022java面试总结,1000道(集合+JVM+并发编程+Spring+Mybatis)的Java高频面试题
    python中openpyxl库用法详解
  • 原文地址:https://blog.csdn.net/m0_47893709/article/details/132902008