当前位置:   article > 正文

Leetcode0547. 省份数量(medium,DFS,BFS,并查集)_省份数量 leetcode

省份数量 leetcode

目录

1. 题目描述

2. 解题分析

3. 代码实现


目录

1. 题目描述

2. 方法一:图遍历

2.1 思路

2.2 代码实现

3. 方法二:并查集

3.1 思路

3.2 代码实现


1. 题目描述

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。

省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。

给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

返回矩阵中 省份 的数量。

示例 1:

输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2

示例 2:

输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3

提示:

  • 1 <= n <= 200
  • n == isConnected.length
  • n == isConnected[i].length
  • isConnected[i][j] 为 1 或 0
  • isConnected[i][i] == 1
  • isConnected[i][j] == isConnected[j][i]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-provinces
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 方法一:图遍历

2.1 思路

        provinces翻译成“省份”实在是不得不服。好在这就是一个符号,不影响解题。

        本质上就是求一个图中的连通区域个数。

        这个图是由isConnected代表的邻接矩阵所表示。

        由于是全图遍历,所以广度优先搜索或者深度优先搜索都可以对付。本“图论基础专题”系列前面已经出现了好几道这样的题目。参考笨牛慢耕的Leetcode每日一解题解笔记(动态更新。。。)中“图论基础专题”。

        邻接矩阵的表示使得查询邻接节点非常方便。

2.2 代码实现

  1. from typing import List
  2. from collections import deque
  3. class Solution:
  4. def findCircleNum(self, isConnected: List[List[int]]) -> int:
  5. if len(isConnected)==0:
  6. return 0
  7. N = len(isConnected)
  8. islandCnt = 0
  9. q = deque()
  10. visited = set()
  11. for node in range(N):
  12. # print(node, visited)
  13. # find the next unvisited node
  14. if node not in visited:
  15. # print("Start node of the next island: ", node)
  16. # Start from this node to search the connected sub-graph
  17. q.append(node)
  18. visited.add(node)
  19. while len(q) > 0:
  20. tmp = q.pop()
  21. for k in range(N):
  22. if isConnected[tmp][k]==1 and k not in visited:
  23. q.append(k)
  24. visited.add(k)
  25. islandCnt += 1
  26. return islandCnt
  27. if __name__ == '__main__':
  28. sln = Solution()
  29. isConnected = [[1,1,0],[1,1,0],[0,0,1]]
  30. print(sln.findCircleNum(isConnected))
  31. isConnected = [[1,0,0],[0,1,0],[0,0,1]]
  32. print(sln.findCircleNum(isConnected))

        以上代码中用的是“q.pop()”,这个与q.append()配对,表示把q当作栈使用,因此代表卓深度优先搜索。而如果改为“q.popleft()”则代表把q当作队列使用,这样就编程了广度优先搜索。 

        执行用时:44 ms, 在所有 Python3 提交中击败了88.42%的用户

        内存消耗:15.4 MB, 在所有 Python3 提交中击败了42.50%的用户

3. 方法二:并查集

3.1 思路

        计算连通分量数的另一个方法是使用并查集(union-find)。初始时,每个省都初始化属于不同的连通分量。遍历矩阵isConnected,如果两个省之间有相连关系,则它们属于同一个连通分量,对它们进行合并。

        遍历矩阵isConnected 的全部元素之后,剩下的连通分量的总数,即为省份的总数。

        在以下实现中,以groupID存储对应节点所属组的ID号。初始化时将每个省初始化为只包含它自己的组。groupID也就是各省自己的ID或者索引号。

        然后从小到大遍历,对于每个省份,查询它邻接的节点中索引号最大的,并将它自己归并到该索引号最大的省所属group。最终,group号没有发生变化的省的个数就是最后剩下的group数,也即本题所求的省份数。

3.2 代码实现

  1. class Solution:
  2. def findCircleNum_union_find(self, isConnected: List[List[int]]) -> int:
  3. def find(index: int) -> int:
  4. # Find the group to which the index belongs
  5. if groupID[index] != index:
  6. groupID[index] = find(groupID[index])
  7. return groupID[index]
  8. def union(index1: int, index2: int):
  9. # Join index1 into the group which index2 belongs to
  10. groupID[find(index1)] = find(index2)
  11. # Initialization.
  12. # Start from the state in which each province belongs to the own-group
  13. # Each group has one province with the same index as its initial root.
  14. groupID = list(range(len(isConnected)))
  15. # For each group, find the (directly or indirectly) connected province and
  16. # join itself into the later group
  17. for i in range(len(isConnected)):
  18. for j in range(i + 1, len(isConnected)):
  19. if isConnected[i][j] == 1:
  20. union(i, j)
  21. numGroup = sum(groupID[i] == i for i in range(len(isConnected)))
  22. return numGroup

        执行用时:56 ms, 在所有 Python3 提交中击败了44.57%的用户

        内存消耗:15.3 MB, 在所有 Python3 提交中击败了54.80%的用户

        回到主目录:笨牛慢耕的Leetcode每日一解题解笔记(动态更新。。。)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/531752
推荐阅读
相关标签
  

闽ICP备14008679号