赞
踩
目录
目录
有 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
provinces翻译成“省份”实在是不得不服。好在这就是一个符号,不影响解题。
本质上就是求一个图中的连通区域个数。
这个图是由isConnected代表的邻接矩阵所表示。
由于是全图遍历,所以广度优先搜索或者深度优先搜索都可以对付。本“图论基础专题”系列前面已经出现了好几道这样的题目。参考笨牛慢耕的Leetcode每日一解题解笔记(动态更新。。。)中“图论基础专题”。
邻接矩阵的表示使得查询邻接节点非常方便。
- from typing import List
- from collections import deque
-
- class Solution:
- def findCircleNum(self, isConnected: List[List[int]]) -> int:
- if len(isConnected)==0:
- return 0
-
- N = len(isConnected)
- islandCnt = 0
- q = deque()
- visited = set()
- for node in range(N):
- # print(node, visited)
- # find the next unvisited node
- if node not in visited:
- # print("Start node of the next island: ", node)
- # Start from this node to search the connected sub-graph
- q.append(node)
- visited.add(node)
- while len(q) > 0:
- tmp = q.pop()
- for k in range(N):
- if isConnected[tmp][k]==1 and k not in visited:
- q.append(k)
- visited.add(k)
- islandCnt += 1
-
- return islandCnt
-
- if __name__ == '__main__':
-
- sln = Solution()
-
- isConnected = [[1,1,0],[1,1,0],[0,0,1]]
- print(sln.findCircleNum(isConnected))
-
- isConnected = [[1,0,0],[0,1,0],[0,0,1]]
- print(sln.findCircleNum(isConnected))
以上代码中用的是“q.pop()”,这个与q.append()配对,表示把q当作栈使用,因此代表卓深度优先搜索。而如果改为“q.popleft()”则代表把q当作队列使用,这样就编程了广度优先搜索。
执行用时:44 ms, 在所有 Python3 提交中击败了88.42%的用户
内存消耗:15.4 MB, 在所有 Python3 提交中击败了42.50%的用户
计算连通分量数的另一个方法是使用并查集(union-find)。初始时,每个省都初始化属于不同的连通分量。遍历矩阵isConnected,如果两个省之间有相连关系,则它们属于同一个连通分量,对它们进行合并。
遍历矩阵isConnected 的全部元素之后,剩下的连通分量的总数,即为省份的总数。
在以下实现中,以groupID存储对应节点所属组的ID号。初始化时将每个省初始化为只包含它自己的组。groupID也就是各省自己的ID或者索引号。
然后从小到大遍历,对于每个省份,查询它邻接的节点中索引号最大的,并将它自己归并到该索引号最大的省所属group。最终,group号没有发生变化的省的个数就是最后剩下的group数,也即本题所求的省份数。
- class Solution:
- def findCircleNum_union_find(self, isConnected: List[List[int]]) -> int:
- def find(index: int) -> int:
- # Find the group to which the index belongs
- if groupID[index] != index:
- groupID[index] = find(groupID[index])
- return groupID[index]
-
- def union(index1: int, index2: int):
- # Join index1 into the group which index2 belongs to
- groupID[find(index1)] = find(index2)
-
- # Initialization.
- # Start from the state in which each province belongs to the own-group
- # Each group has one province with the same index as its initial root.
- groupID = list(range(len(isConnected)))
-
- # For each group, find the (directly or indirectly) connected province and
- # join itself into the later group
- for i in range(len(isConnected)):
- for j in range(i + 1, len(isConnected)):
- if isConnected[i][j] == 1:
- union(i, j)
-
- numGroup = sum(groupID[i] == i for i in range(len(isConnected)))
- return numGroup
执行用时:56 ms, 在所有 Python3 提交中击败了44.57%的用户
内存消耗:15.3 MB, 在所有 Python3 提交中击败了54.80%的用户
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。