Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1733. Minimum Number of People to Teach - Leetcode Solution

Problem Description

You are given an integer n representing the number of people in a social network, where each person is labeled from 1 to n. Each person may know exactly one language, as described by the languages list, where languages[i] is a list of languages known by the ith person. You are also given a list of friendships, where each element is a pair [u, v] that means person u and person v are friends.

Two friends can communicate only if they share at least one common language. Your task is to determine the minimum number of people you must teach a single language so that all friendships can communicate. You may choose any language to teach, and each person can be taught at most one language.

Constraints:

  • Each person knows at least one language.
  • Each friendship is unique and unordered.
  • You may not reuse elements (i.e., you cannot teach a person two languages).
  • There is always at least one valid solution.

Thought Process

At first glance, it seems you might need to teach as many people as possible to cover all possible friendships, but that's inefficient. Instead, the key is to focus only on the friendships where the two friends cannot communicate (i.e., they have no common language).

For each such "problematic" friendship, you need to make at least one of the two people learn a new language so that they can communicate. However, since you can choose which language to teach, you want to minimize the total number of people taught by picking the language that covers the most "problematic" people.

The brute-force approach would be to try teaching every possible language to all problematic people and count how many people need to learn it. The optimized idea is to focus on the language that is already known by the most problematic people, so you teach the rest of the problematic people that language.

Solution Approach

  • Step 1: Identify Problematic Friendships
    • Go through each friendship pair [u, v].
    • Check if languages[u] and languages[v] have any intersection.
    • If not, add both u and v to a set of "problematic" people.
  • Step 2: Count Language Coverage
    • For each language, count how many problematic people already know it.
    • This is done using a hash map (dictionary) for O(1) lookups.
  • Step 3: Choose the Best Language to Teach
    • For each language, calculate how many problematic people do not know it.
    • The minimum of these numbers over all languages is your answer.
  • Step 4: Return the Result
    • Return the minimum number of problematic people who need to be taught the chosen language.

By focusing only on problematic people and maximizing the reuse of existing language knowledge, you minimize the number of teachings.

Example Walkthrough

Input:
n = 3
languages = [[1], [2], [3]]
friendships = [[1,2],[2,3],[1,3]]

Step 1: Identify Problematic Friendships
- (1,2): Person 1 knows [1], Person 2 knows [2]. No overlap. Both are problematic.
- (2,3): [2] vs [3]. No overlap. Both are problematic.
- (1,3): [1] vs [3]. No overlap. Both are problematic.
Problematic people: {1,2,3}

Step 2: Language Coverage
- Language 1: Only person 1 knows it.
- Language 2: Only person 2 knows it.
- Language 3: Only person 3 knows it.

Step 3: Minimum to Teach
- If we pick language 1: Teach to 2 and 3 (2 people).
- If we pick language 2: Teach to 1 and 3 (2 people).
- If we pick language 3: Teach to 1 and 2 (2 people).
Answer: 2

Time and Space Complexity

Brute-force:
- For each language, for each problematic person, check if they know it.
- Complexity: O(L * P), where L is the number of languages and P is the number of problematic people.

Optimized Approach:
- Identifying problematic friendships: O(F * K), where F is the number of friendships and K is the average number of languages per person.
- Counting language coverage: O(P * K), where P is the number of problematic people.
- Final pass over languages: O(L).
- Total: O(F * K + P * K + L)

Space: O(N * K) for storing language sets, plus O(P) for problematic people, and O(L) for language counts.

Summary

The key insight is to focus only on friendships where communication is not possible, and only on the people involved in those friendships. By choosing the language that is already most common among these problematic people, you minimize the number of teachings required. This approach is efficient and leverages hash maps and set operations for fast lookups, making it both practical and elegant.

Code Implementation

class Solution:
    def minimumTeachings(self, n, languages, friendships):
        # Convert to 0-based index for easier handling
        lang_sets = [set(langs) for langs in languages]
        problematic = set()
        for u, v in friendships:
            u -= 1; v -= 1
            if not (lang_sets[u] & lang_sets[v]):
                problematic.add(u)
                problematic.add(v)
        if not problematic:
            return 0
        # Count for each language how many problematic people already know it
        from collections import Counter
        lang_count = Counter()
        for person in problematic:
            for lang in lang_sets[person]:
                lang_count[lang] += 1
        # For each language, compute how many problematic people do NOT know it
        min_teach = float('inf')
        for lang in range(1, n+1):
            teach = len(problematic) - lang_count.get(lang, 0)
            min_teach = min(min_teach, teach)
        return min_teach
      
class Solution {
public:
    int minimumTeachings(int n, vector<vector<int>>& languages, vector<vector<int>>& friendships) {
        int m = languages.size();
        vector<unordered_set<int>> lang_sets(m);
        for (int i = 0; i < m; ++i) {
            for (int l : languages[i]) lang_sets[i].insert(l);
        }
        unordered_set<int> problematic;
        for (auto& f : friendships) {
            int u = f[0] - 1, v = f[1] - 1;
            bool can_communicate = false;
            for (int l : lang_sets[u]) {
                if (lang_sets[v].count(l)) {
                    can_communicate = true;
                    break;
                }
            }
            if (!can_communicate) {
                problematic.insert(u);
                problematic.insert(v);
            }
        }
        if (problematic.empty()) return 0;
        vector<int> lang_count(n+1, 0);
        for (int person : problematic) {
            for (int l : lang_sets[person]) {
                lang_count[l]++;
            }
        }
        int min_teach = problematic.size();
        for (int lang = 1; lang <= n; ++lang) {
            min_teach = min(min_teach, (int)problematic.size() - lang_count[lang]);
        }
        return min_teach;
    }
};
      
class Solution {
    public int minimumTeachings(int n, int[][] languages, int[][] friendships) {
        int m = languages.length;
        List<Set<Integer>> langSets = new ArrayList<>();
        for (int[] langs : languages) {
            Set<Integer> set = new HashSet<>();
            for (int l : langs) set.add(l);
            langSets.add(set);
        }
        Set<Integer> problematic = new HashSet<>();
        for (int[] f : friendships) {
            int u = f[0] - 1, v = f[1] - 1;
            Set<Integer> setU = langSets.get(u), setV = langSets.get(v);
            boolean canCommunicate = false;
            for (int l : setU) {
                if (setV.contains(l)) {
                    canCommunicate = true;
                    break;
                }
            }
            if (!canCommunicate) {
                problematic.add(u);
                problematic.add(v);
            }
        }
        if (problematic.isEmpty()) return 0;
        int[] langCount = new int[n+1];
        for (int person : problematic) {
            for (int l : langSets.get(person)) {
                langCount[l]++;
            }
        }
        int minTeach = problematic.size();
        for (int lang = 1; lang <= n; ++lang) {
            minTeach = Math.min(minTeach, problematic.size() - langCount[lang]);
        }
        return minTeach;
    }
}
      
var minimumTeachings = function(n, languages, friendships) {
    const langSets = languages.map(langs => new Set(langs));
    const problematic = new Set();
    for (const [u, v] of friendships) {
        const u0 = u - 1, v0 = v - 1;
        let canCommunicate = false;
        for (const l of langSets[u0]) {
            if (langSets[v0].has(l)) {
                canCommunicate = true;
                break;
            }
        }
        if (!canCommunicate) {
            problematic.add(u0);
            problematic.add(v0);
        }
    }
    if (problematic.size === 0) return 0;
    const langCount = new Array(n+1).fill(0);
    for (const person of problematic) {
        for (const l of langSets[person]) {
            langCount[l]++;
        }
    }
    let minTeach = problematic.size;
    for (let lang = 1; lang <= n; ++lang) {
        minTeach = Math.min(minTeach, problematic.size - langCount[lang]);
    }
    return minTeach;
};