【力扣“图论基础”学习计划】之好题分享与知识点总结

前言

把力扣学习计划之图论基础写完了,萌生出挑出几道我觉得好的题目出来的想法。

在“图论基础”学习计划中搜索占主体。本篇博客也将围绕搜索展开。

搜索中抓住:方向 + 去重

知识点:(循循渐进)

  1. 邻接矩阵
  2. 在矩阵中的搜索,这里更偏向 bfs 搜索,但是和 dfs 差不多,都是向四周拓展
  3. 邻接链表和在图中的搜索
  4. 计数搜索、起点到终点的最小步数搜索
  5. 二分图

题目 点击蓝色的文字跳转链接

一、岛屿数量(好经典的一道题)

解法:bfs、dfs、并查集。

这道题的评论区有很多优质解法,不再赘述。

写完这道题后你将了解 邻接矩阵、直观的搜索。

二、太平洋大西洋水流问题

知识点:多源bfs ,不了解的读者可以参考我原来的写过的一篇博客

什么是 多源bfs ? 无非是普通bfs初始化的时候把符合某条件的点全部加进队列中。

三、省份数量

知识点:邻接链表图的深度优先搜索

对于每一个点搜索所有与他相连的点、并一直搜到底。

写了这题后读者将对图的常规表示形式(邻接矩阵、邻接链表)有一个大致的了解。

还有一种表示形式是结构体数组,只存储边的信息。感兴趣的读者可以翻阅我之前的博客学习Kruskal算法。

四、水壶问题

知识点:抽象图的 bfs

不是在图中的遍历,但是有 bfs 的特征。

搜索的本质是什么?我的理解是每次将所有可能加入队列、像一滴墨水滴入水中不停扩散、直到到达终点。

这题的难点是如何用哈希表表示pair。这里使用自定义哈希函数来存储pair。用到的函数是decltype,同样用到过该函数的有堆的自定义排序

typedef pair<int, int> PII;

class Solution {
public:
    bool canMeasureWater(int a, int b, int c) {
        queue<PII> q; //a b
        q.push({0, 0});
        auto hash_function = [](const PII &o) {
            return hash<int>()(o.first) ^ hash<int>()(o.second);
        };
        unordered_set<PII, decltype(hash_function)> seen(0, hash_function);

        while(q.size())
        {
            auto [x, y] = q.front(); q.pop();
            if(x == c || y == c || x + y == c) return true;
            if(seen.count({x, y})) continue;
            seen.emplace(x, y);
            
            //全x 全y 空x 空y x->y y->x
            q.push({a, y});
            q.push({x, b});
            q.push({0, y});
            q.push({x, 0});
            q.push({x - min(x, b - y), y + min(x, b - y)});
            q.push({x + min(a - x, y), y - min(a - x, y)});
        }
        return false;
    }
};

五、最小基因变化

知识点:起点到终点带中间限制的最小步数

模板如下:

unordered_set<set> Set(a.begin(), a.end()); //查询 a是题目给的限制表
unordered_map<string, int> m; //word step 去重+计数
queue<string> q; //bfs
while(q.size())
{
    auto it = q.front(); q.pop();
    int val = m[it];
    if(it == end) return val; //到了终点
    for(int i = 0; i < it.size(); ++ i) 
    {
        string s = it; //这里依据题目决定写在哪个循环的里面
        for(int j = 0; j < t; ++ j) //次数依题意 含义是向外拓展所有可能
        {
            s[i] = j;
            if(Set.count(s) && !m.count(s)) //与限制表挂钩 + 去重 + 计数
            {
                m.insert({s, val + 1});
                q.push(s);
            }
        }
    }
}

这题的 AC 代码:

class Solution {
public:
    //bfs 将每一步能到达的加到队列里面
    char ch[4] = {'A', 'C', 'G', 'T'};
    int minMutation(string start, string end, vector<string>& bank) {
        unordered_set<string> bankSet(bank.begin(), bank.end());
        if(!bankSet.count(end)) return -1;
        unordered_map<string, int> m;
        m.insert({start, 0});
        queue<string> q;
        q.push(start);
        while(q.size())
        {
            string s = q.front(); q.pop();
            int val = m[s];
            if(s == end) return val;
            for(int i = 0; i < 8; ++ i)
            {
                string ss = s;
                for(int j = 0; j < 4; ++ j)
                {
                    ss[i] = ch[j];
                    if(bankSet.count(ss) && !m.count(ss))
                    {
                        m[ss] = val + 1;
                        q.push(ss);
                    }
                }
            }
        }
        return -1;
    }
};

还有两个类似的题目供读者自测:

  1. 打开转盘锁
  2. 单词接龙

六、可能的二分法

知识点:二分图。读者看了这篇博客后能直接 AC

小结

  1. 力扣的图论基础入门难度挺友好的🤣kuangbin 的图练习人快写麻了。
  2. 基础题集围绕的全是搜索。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值