朋友圈

2020-06-22 18:13 更新

題目

班上有 N 名學(xué)生。其中有些人是朋友,有些則不是。他們的友誼具有是傳遞性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我們可以認(rèn)為 A 也是 C 的朋友。所謂的朋友圈,是指所有朋友的集合。

給定一個(gè) N * N 的矩陣 M,表示班級中學(xué)生之間的朋友關(guān)系。如果M[i][j] = 1,表示已知第 i 個(gè)和 j 個(gè)學(xué)生互為朋友關(guān)系,否則為不知道。你必須輸出所有學(xué)生中的已知的朋友圈總數(shù)。

示例 1:

輸入: [[1,1,0], [1,1,0], [0,0,1]] 輸出: 2 說明:已知學(xué)生0和學(xué)生1互為朋友,他們在一個(gè)朋友圈。 第2個(gè)學(xué)生自己在一個(gè)朋友圈。所以返回2。

示例 2:

輸入: [[1,1,0], [1,1,1], [0,1,1]] 輸出: 1 說明:已知學(xué)生0和學(xué)生1互為朋友,學(xué)生1和學(xué)生2互為朋友,所以學(xué)生0和學(xué)生2也是朋友,所以他們?nèi)齻€(gè)在一個(gè)朋友圈,返回1。

注意:

N 在[1,200]的范圍內(nèi)。 對于所有學(xué)生,有M[i][i] = 1。 如果有M[i][j] = 1,則有M[j][i] = 1。

題解一:深度優(yōu)先搜索

給定的矩陣可以看成圖的鄰接矩陣。這樣我們的問題可以變成無向圖連通塊的個(gè)數(shù)。為了方便理解,考慮如下矩陣:

  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]

,點(diǎn)的編號表示矩陣 M 的下標(biāo),iii 和 jjj 之間有一條邊當(dāng)且僅當(dāng) M[i][j]M[i][j]M[i][j] 為 1。 為了找到連通塊的個(gè)數(shù),一個(gè)簡單的方法就是使用深度優(yōu)先搜索,從每個(gè)節(jié)點(diǎn)開始,我們使用一個(gè)大小為 NNN 的 visitedvisitedvisited 數(shù)組(MMM 大小為 N×NN \times NN×N),這樣 visited[i]visited[i]visited[i] 表示第 i 個(gè)元素是否被深度優(yōu)先搜索訪問過。 我們首先選擇一個(gè)節(jié)點(diǎn),訪問任一相鄰的節(jié)點(diǎn)。然后再訪問這一節(jié)點(diǎn)的任一相鄰節(jié)點(diǎn)。這樣不斷遍歷到?jīng)]有未訪問的相鄰節(jié)點(diǎn)時(shí),回溯到之前的節(jié)點(diǎn)進(jìn)行訪問。

  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. }

題解二:廣度優(yōu)先搜索

  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))
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號