朋友圈

2020-06-22 18:13 更新

题目

班上有 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。

注意:

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

题解一:深度优先搜索

给定的矩阵可以看成图的邻接矩阵。这样我们的问题可以变成无向图连通块的个数。为了方便理解,考虑如下矩阵:

  1. M= [1 1 0 0 0 0
  2. 1 1 0 0 0 0
  3. 0 0 1 1 1 0
  4. 0 0 1 1 0 0
  5. 0 0 1 0 1 0
  6. 0 0 0 0 0 1]

,点的编号表示矩阵 M 的下标,iii 和 jjj 之间有一条边当且仅当 M[i][j]M[i][j]M[i][j] 为 1。 为了找到连通块的个数,一个简单的方法就是使用深度优先搜索,从每个节点开始,我们使用一个大小为 NNN 的 visitedvisitedvisited 数组(MMM 大小为 N×NN \times NN×N),这样 visited[i]visited[i]visited[i] 表示第 i 个元素是否被深度优先搜索访问过。 我们首先选择一个节点,访问任一相邻的节点。然后再访问这一节点的任一相邻节点。这样不断遍历到没有未访问的相邻节点时,回溯到之前的节点进行访问。

  1. public class Solution {
  2. public void dfs(int[][] M, int[] visited, int i) {
  3. for (int j = 0; j < M.length; j++) {
  4. if (M[i][j] == 1 && visited[j] == 0) {
  5. visited[j] = 1;
  6. dfs(M, visited, j);
  7. }
  8. }
  9. }
  10. public int findCircleNum(int[][] M) {
  11. int[] visited = new int[M.length];
  12. int count = 0;
  13. for (int i = 0; i < M.length; i++) {
  14. if (visited[i] == 0) {
  15. dfs(M, visited, i);
  16. count++;
  17. }
  18. }
  19. return count;
  20. }
  21. }

题解二:广度优先搜索

  1. public class Solution {
  2. public int findCircleNum(int[][] M) {
  3. int[] visited = new int[M.length];
  4. int count = 0;
  5. Queue < Integer > queue = new LinkedList < > ();
  6. for (int i = 0; i < M.length; i++) {
  7. if (visited[i] == 0) {
  8. queue.add(i);
  9. while (!queue.isEmpty()) {
  10. int s = queue.remove();
  11. visited[s] = 1;
  12. for (int j = 0; j < M.length; j++) {
  13. if (M[s][j] == 1 && visited[j] == 0)
  14. queue.add(j);
  15. }
  16. }
  17. count++;
  18. }
  19. }
  20. return count;
  21. }
  22. }

题解三:并查集

  1. public class Solution {
  2. int find(int parent[], int i) {
  3. if (parent[i] == -1)
  4. return i;
  5. return find(parent, parent[i]);
  6. }
  7. void union(int parent[], int x, int y) {
  8. int xset = find(parent, x);
  9. int yset = find(parent, y);
  10. if (xset != yset)
  11. parent[xset] = yset;
  12. }
  13. public int findCircleNum(int[][] M) {
  14. int[] parent = new int[M.length];
  15. Arrays.fill(parent, -1);
  16. for (int i = 0; i < M.length; i++) {
  17. for (int j = 0; j < M.length; j++) {
  18. if (M[i][j] == 1 && i != j) {
  19. union(parent, i, j);
  20. }
  21. }
  22. }
  23. int count = 0;
  24. for (int i = 0; i < parent.length; i++) {
  25. if (parent[i] == -1)
  26. count++;
  27. }
  28. return count;
  29. }
  30. }

python3

  1. class Solution:
  2. def findCircleNum(self, M) -> int:
  3. father = [i for i in range(len(M))]
  4. def find(a):
  5. if father[a] != a: father[a] = find(father[a])
  6. return father[a]
  7. def union(a, b):
  8. father[find(b)] = find(a)
  9. return find(b)
  10. for a in range(len(M)):
  11. for b in range(a):
  12. if M[a][b]: union(a, b)
  13. for i in range(len(M)): find(i)
  14. return len(set(father))
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号