Leetcode 547:朋友圈(超详细的解法!!!)

班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。

给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。

示例 1:

输入: 
[[1,1,0],
 [1,1,0],
 [0,0,1]]
输出: 2 
说明:已知学生0和学生1互为朋友,他们在一个朋友圈。
第2个学生自己在一个朋友圈。所以返回2。

示例 2:

输入: 
[[1,1,0],
 [1,1,1],
 [0,1,1]]
输出: 1
说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。

注意:

  1. N 在[1,200]的范围内。
  2. 对于所有学生,有M[i][i] = 1。
  3. 如果有M[i][j] = 1,则有M[j][i] = 1。

解题思路

这是一个很简单的题目,显然是通过并查集来做。通过遍历矩阵生成相应的并查集,然后返回所有的根节点数量即可。

class Solution:
    def findCircleNum(self, M: 'List[List[int]]') -> 'int':
        n = len(M)
        s = UF(n)
        for i in range(n):
            for j in range(n):
                if M[i][j]:
                    s.union(i, j)
        
        res = set()
        for i in range(n):
            res.add(s.find(i))
        return len(res)
                    
class UF:
    def __init__(self, n):
        self.parents = list(range(n+1))
        self.ranks = [0]*(n+1)

    def find(self, x):
        if x != self.parents[x]:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]
    
    def union(self, x, y):
        i, j = self.find(x), self.find(y)
        if self.ranks[i] > self.ranks[j]:
            self.parents[j] = i
        if self.ranks[j] > self.ranks[i]:
            self.parents[i] = j
        if self.ranks[i] == self.ranks[j]:
            self.parents[i] = j
            self.ranks[j] += 1

我们可以将代码写的更加简洁

class Solution:
    def findCircleNum(self, M: 'List[List[int]]') -> 'int':
        n = len(M)
        parents = list(range(n))
        def find(x):
            if x != parents[x]:
                parents[x] = find(parents[x])
            return parents[x]
    
        for i in range(n):
            for j in range(n):
                if M[i][j]:
                    parents[find(i)] = find(j)
        res = set()
        for i in range(n):
            res.add(find(i))
        return len(res)

很多时候并查集可以处理的问题,也可以通过DFS处理,这个问题就是这样。

class Solution:
    def findCircleNum(self, M: 'List[List[int]]') -> 'int':
        n = len(M)
        visited = [0]*n
        res = 0
        
        def dfs(i):
            for j in range(n):
                if M[i][j] and visited[j] == 0:
                    visited[j] = 1
                    dfs(j)
                
        for i in range(n):
            if visited[i] == 0:
                dfs(i)
                res += 1
                
        return res

reference:

https://leetcode.com/problems/friend-circles/discuss/101338/Neat-DFS-java-solution

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

你可能感兴趣的:(Problems,leetcode解题指南)