算法:图

图的算法题通常有两种:1.深度优先或广度优先;2.并查集

1.深度优先or广度优先,通过dfs或者bfs遍历图。
2.并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。
并查集可以理解为一种解决问题的思想,将有关系的元素合并为一个集合。
并查集编写的核心通常在于find函数或者叫getParent
并查集详解 ——图文解说,简单易懂(转)

相关题目

面试题 16.19. 水域大小

面试题 16.19. 水域大小

LeetCode 200. 岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
LeetCode 200. 岛屿数量
1.深度优先遍历,并标记数组

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        row = len(grid)
        if row == 0:
            return 0
        col = len(grid[0])
        l = [(-1,0), (0,-1), (0,1), (1,0)]
        def helper(i,j):
            grid[i][j] = '0'
            for t in l:
                x, y = i+t[0], j+t[1]
                if 0<=x<row and 0<=y<col and grid[x][y]=='1':
                    helper(x,y)
    
        ans = 0
        for i in range(row):
            for j in range(col):
                if grid[i][j] == '1':
                    ans += 1
                    helper(i,j)
        return ans

2.并查集

class Union:
    def __init__(self, row, col):
        self.parent = [i for i in range(row * col)]
        self.count = 0  # 合并的个数

    def union(self, i, j):
        # 合并两个节点 输入按照:i < j
        parent = self.parent
        while parent[i] != i:
            i = parent[i]
        while parent[j] != j:
            j = parent[j]
        if i != j:
            self.count += 1
            if i<=j:
                parent[j] = i
            else:
                parent[i] = j

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        row = len(grid)
        if row == 0:
            return 0
        col = len(grid[0])
        union = Union(row, col)
        l = [(-1, 0), (0, -1)]
        ans = 0  # 1的个数
        for i in range(row):
            for j in range(col):
                if grid[i][j] == '1':
                    ans += 1
                    for t in l:
                        x, y = i + t[0], j + t[1]
                        if 0 <= x < row and 0 <= y < col and grid[x][y] == '1':
                            union.union(x * col + y, i * col + j)

        return ans - union.count  # 1的个数-合并的个数

面试题 17.07. 婴儿名字

每年,政府都会公布一万个最常见的婴儿名字和它们出现的频率,也就是同名婴儿的数量。有些名字有多种拼法,例如,John 和 Jon 本质上是相同的名字,但被当成了两个名字公布出来。给定两个列表,一个是名字及对应的频率,另一个是本质相同的名字对。设计一个算法打印出每个真实名字的实际频率。注意,如果 John 和 Jon 是相同的,并且 Jon 和 Johnny 相同,则 John 与 Johnny 也相同,即它们有传递和对称性。
在结果列表中,选择 字典序最小 的名字作为真实名字。

class Solution:
    def trulyMostPopular(self, names: List[str], synonyms: List[str]) -> List[str]:
        d = {}  # name和frequency
        union_d = {}  # 并查集,节点为key:父节点为value
        for name in names:
            idx = name.find('(')
            s1 = name[:idx]
            num = int(name[idx+1:-1])
            d[s1] = num
        for s in synonyms:
            idx = s.find(',')
            s1 = s[1:idx]
            s2 = s[idx+1:-1]
            while s1 in union_d:
                s1 = union_d[s1]
            while s2 in union_d:
                s2 = union_d[s2]
            if s1 != s2:
                s_min, s_max = min(s1, s2), max(s1, s2)
                union_d[s_max] = s_min
                d[s_min] = d.get(s_max, 0) + d.get(s_min, 0)
                if s_max in d:
                    del d[s_max]

        ans = [k + '(' + str(v) + ')' for k,v in d.items()]
        return ans

面试题 17.07. 婴儿名字

LeetCode 399. 除法求值

给你一个变量对数组 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 的情况,且不存在任何矛盾的结果。
注意:未在等式列表中出现的变量是未定义的,因此无法确定它们的答案。
LeetCode 399. 除法求值

class Solution {
private:
    class Union{
        public:
            vector<int> parent;
            vector<double> w;
        Union(int n){
            parent = vector<int>(n,0);
            w = vector<double>(n,1.0);
            for(int i=0;i<n;++i){
                parent[i] = i;//初始化每个元素的parent为自己
            }
        }
        int getParent(int x){
            if(x!=parent[x]){
                int t = parent[x];
                parent[x] = getParent(t);
                //1.未遍历过需要相乘 以a/b b/c为例 需要更新a/c,这里只需更新a/b,因为b/c在递归中已经更新过 2.已更新过,c的父节点还是c,所以结果不变
                w[x] = w[x]*w[t];
            }
            return parent[x];
        }
        //两者的根不同则进行合并
        void add(int a, int b, double val){
            int pa = getParent(a);
            int pb = getParent(b);
            if(pa!=pb){
                parent[pa] = pb;
                w[pa] = w[b]/w[a]*val;
            }
        }
        double getW(int a, int b){
            if(getParent(a) == getParent(b)){
                return w[a]/w[b];
            }
            return -1.0;
        }
    };
public:
    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
        unordered_map<string, int> ump;
        int n = (int)equations.size();
        for (int i = 0; i < n; ++i) {
            if (!ump.count(equations[i][0])) ump.insert({ equations[i][0],ump.size() });
            if (!ump.count(equations[i][1])) ump.insert({ equations[i][1],ump.size() });
        }
        int m = (int)ump.size();
        Union un = Union(m);
        for(int i=0;i<n;++i){
            un.add(ump[equations[i][0]], ump[equations[i][1]], values[i]);
        }
        vector<double> res;
        for(auto& v: queries){
            if(ump.count(v[0]) && ump.count(v[1])){
                res.emplace_back(un.getW(ump[v[0]], ump[v[1]]));
            }else res.emplace_back(-1.0); 
        }
        return res;
    }
};
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值