Friend Circles

Here is a medium Leetcode problem: https://leetcode.com/problems/friend-circles/

There are N students in a class. Some of them are friends, while some are not. Their friendship is transitive in nature. For example, if A is a direct friend of B, and B is a direct friend of C, then A is an indirect friend of C. And we defined a friend circle is a group of students who are direct or indirect friends.
Given a N*N matrix M representing the friend relationship between students in the class. If M[i][j] = 1, then the ith and jthstudents are direct friends with each other, otherwise not. And you have to output the total number of friend circles among all the students.
Example 1:
Input: 
[[1,1,0],
 [1,1,0],
 [0,0,1]]
Output: 2
Explanation:The 0th and 1st students are direct friends, so they are in a friend circle. 
The 2nd student himself is in a friend circle. So return 2.
Example 2:
Input: 
[[1,1,0],
 [1,1,1],
 [0,1,1]]
Output: 1
Explanation:The 0th and 1st students are direct friends, the 1st and 2nd students are direct friends, 
so the 0th and 2nd students are indirect friends. All of them are in the same friend circle, so return 1.
Note:
  1. N is in range [1,200].
  2. M[i][i] = 1 for all students.
  3. If M[i][j] = 1, then M[j][i] = 1.
Here is a solution:
a) Have a function that recursively given a row marks up all the friends connected to that row
b) It modifies the input grid M by resetting the connections to zero
c) The outer loop just goes thru all the rows calling (a) and incrementing the counter accordingly

If I'm not mistaken, each row won't be visited more than 2x, hence I'd put the time-complexity somewhere in the O(2*N^2) range, which would be 80,000 steps - very quick. Cheers, ACC.


public class Solution
{
 public int FindCircleNum(int[][] M)
 {
  int count = 0;
  for (int r = 0; r < M.GetLength(0); r++)
  {
   bool found = false;
   FindCircleNum(M, r, new Hashtable(), ref found);
   if (found) count++;
  }

  return count;
 }

 private void FindCircleNum(int[][] M, int row, Hashtable seenRow, ref bool found)
 {
  if (seenRow.ContainsKey(row)) return;
  seenRow.Add(row, true);
  for (int c = 0; c < M[0].GetLength(0); c++)
  {
   if (M[row][c] == 1)
   {
    M[row][c] = 0;
    M[c][row] = 0;
    found = true;
    FindCircleNum(M, c, seenRow, ref found);
   }
  }
 }
}

Comments

  1. Nice! Since M is not immutable, it's also possible to save space by mutating it to track explored cells.

    impl Solution {
    pub fn find_circle_num(m: Vec>) -> i32 {
    let mut seen = vec![false; m.len()];

    fn dfs(m: &Vec>, i: usize, seen: &mut [bool]) {
    for j in 0..m.len() {
    if m[i][j] == 1 && !seen[j] {
    seen[j] = true;
    dfs(&m, j, seen);
    }
    }
    }

    let mut num = 0;
    for i in 0..m.len() {
    if seen[i] {
    continue;
    }
    dfs(&m, i, &mut seen);
    num += 1;
    }
    num
    }
    }

    https://gist.github.com/ttsugriy/48bc9cf6b52b8b0b983e13e66b1f70da

    ReplyDelete

Post a Comment

Popular posts from this blog

Golang vs. C#: performance characteristics (simple case study)

Claude vs ChatGPT: A Coder's Perspective on LLM Performance

The Power Sum, a recursive problem by HackerRank