LeetCode #924 Minimize Malware Spread 儘量減少惡意軟件的傳播 924 Minimize Malware Spread 儘量減少惡意軟件的傳播

924 Minimize Malware Spread 儘量減少惡意軟件的傳播

Description:
You are given a network of n nodes represented as an n x n adjacency matrix graph, where the ith node is directly connected to the jth node if graph[i][j] == 1.

Some nodes initial are initially infected by malware. Whenever two nodes are directly connected, and at least one of those two nodes is infected by malware, both nodes will be infected by malware. This spread of malware will continue until no more nodes can be infected in this manner.

Suppose M(initial) is the final number of nodes infected with malware in the entire network after the spread of malware stops. We will remove exactly one node from initial.

Return the node that, if removed, would minimize M(initial). If multiple nodes could be removed to minimize M(initial), return such a node with the smallest index.

Note that if a node was removed from the initial list of infected nodes, it might still be infected later due to the malware spread.

Example:

Example 1:

Input: graph = [[1,1,0],[1,1,0],[0,0,1]], initial = [0,1]
Output: 0

Example 2:

Input: graph = [[1,0,0],[0,1,0],[0,0,1]], initial = [0,2]
Output: 0

Example 3:

Input: graph = [[1,1,1],[1,1,1],[1,1,1]], initial = [1,2]
Output: 1

Constraints:

n == graph.length
n == graph[i].length
2 <= n <= 300
graph[i][j] is 0 or 1.
graph[i][j] == graph[j][i]
graph[i][i] == 1
1 <= initial.length <= n
0 <= initial[i] <= n - 1
All the integers in initial are unique.

題目描述:
在節點網絡中,只有當 graph[i][j] = 1 時,每個節點 i 能夠直接連接到另一個節點 j。

一些節點 initial 最初被惡意軟件感染。只要兩個節點直接連接,且其中至少一個節點受到惡意軟件的感染,那麼兩個節點都將被惡意軟件感染。這種惡意軟件的傳播將繼續,直到沒有更多的節點可以被這種方式感染。

假設 M(initial) 是在惡意軟件停止傳播之後,整個網絡中感染惡意軟件的最終節點數。

如果從初始列表中移除某一節點能夠最小化 M(initial), 返回該節點。如果有多個節點滿足條件,就返回索引最小的節點。

請注意,如果某個節點已從受感染節點的列表 initial 中刪除,它以後可能仍然因惡意軟件傳播而受到感染。

示例 :

示例 1:

輸入:graph = [[1,1,0],[1,1,0],[0,0,1]], initial = [0,1]
輸出:0

示例 2:

輸入:graph = [[1,0,0],[0,1,0],[0,0,1]], initial = [0,2]
輸出:0

示例 3:

輸入:graph = [[1,1,1],[1,1,1],[1,1,1]], initial = [1,2]
輸出:1

提示:

1 < graph.length = graph[0].length <= 300
0 <= graph[i][j] == graph[j][i] <= 1
graph[i][i] == 1
1 <= initial.length < graph.length
0 <= initial[i] < graph.length

思路:

並查集
先將圖中有關聯的連在一個根節點中
對於並查集中的集合找到只有一個被感染的節點的集合
計算上述最大的集合並更新結果
時間複雜度爲 O(n ^ 2), 空間複雜度爲 O(n)

代碼:
C++:

class UF 
{
private:
    vector<int> parent;
    vector<int> weight;
    int count;
public:
    UF(int n) 
    {
        parent = vector<int>(n);
        weight = vector<int>(n, 1);
        count = n;
        for (int i = 0; i < n; i++) parent[i] = i;
    }
    
    int find(int p) 
    {
        return p == parent[p] ? parent[p] : (parent[p] = find(parent[p]));
    }
    
    void connect(int p, int q) 
    {
        p = find(p);
        q = find(q);
        if (p == q) return;
        if (weight[p] > weight[q]) 
        {
            parent[q] = p;
            weight[p] += weight[q];
        }
        else 
        {
            parent[p] = q;
            weight[q] += weight[p];
        }
        --count;
    }
};
class Solution 
{
public:
    int minMalwareSpread(vector<vector<int>>& graph, vector<int>& initial) 
    {
        sort(initial.begin(), initial.end());
        int n = graph.size(), m = initial.size(), result = initial.front(), count = 0;
        UF uf(n);
        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if (graph[i][j] == 1) uf.connect(i, j);
        for (int i = 0; i < m; i++) {
            int root = uf.find(initial[i]);
            bool flag = true;
            for (int j = 0; j < m; j++) {
                if (i == j) continue;
                if (uf.find(initial[j]) == root) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                int cost = 0;
                for (int k = 0; k < n; k++) if (uf.find(k) == root) ++cost;
                if (cost > count) {
                    count = cost;
                    result = initial[i];
                }
            }
        }
        return result;
    }
};

Java:

class UF {
    private int[] parent;
    private int[] weight;
    private int count;
    
    public UF(int n) {
        this.parent = new int[n];
        this.weight = new int[n];
        this.count = n;
        for (int i = 0; i < n; i++) {
            parent[i] = i;
            weight[i] = 1;
        }
    }
    
    public int find(int p) {
        return p == parent[p] ? parent[p] : (parent[p] = find(parent[p]));
    }
    
    public void union(int p, int q) {
        p = find(p);
        q = find(q);
        if (p == q) return;
        if (weight[p] > weight[q]) {
            parent[q] = p;
            weight[p] += weight[q];
        }
        else {
            parent[p] = q;
            weight[q] += weight[p];
        }
        --count;
    }
}
class Solution {
    public int minMalwareSpread(int[][] graph, int[] initial) {
        Arrays.sort(initial);
        int n = graph.length, m = initial.length, result = initial[0], count = 0;
        UF uf = new UF(n);
        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if (graph[i][j] == 1) uf.union(i, j);
        for (int i = 0; i < m; i++) {
            int root = uf.find(initial[i]);
            boolean flag = true;
            for (int j = 0; j < m; j++) {
                if (i == j) continue;
                if (uf.find(initial[j]) == root) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                int cost = 0;
                for (int k = 0; k < n; k++) if (uf.find(k) == root) ++cost;
                if (cost > count) {
                    count = cost;
                    result = initial[i];
                }
            }
        }
        return result;
    }
}

Python:

class Solution:
    def minMalwareSpread(self, graph: [[int]], initial: [int]) -> int:
        class UF:
            def __init__(self, n: int) -> None:
                self.parent = [i for i in range(n)]
                self.weight = [1] * n
                self.count = n

            def union(self, p: int, q: int) -> None:
                """
                連接兩個點
                :param p: 一個節點
                :param q: 另一個節點
                :return:
                """
                p = self.find(p)
                q = self.find(q)
                if p == q:
                    return
                if self.weight[p] > self.weight[q]:
                    self.parent[q] = p
                    self.weight[p] += self.weight[q]
                else:
                    self.parent[p] = q
                    self.weight[q] += self.weight[p]
                self.count -= 1

            def connected(self, p: int, q: int) -> bool:
                """
                檢查兩個點是否在同一分量
                :param p: 一個節點
                :param q: 另一個節點
                :return: 返回兩個點是否在同一個分量
                """
                return self.find(p) == self.find(q)

            def find(self, p: int) -> int:
                """
                查找根節點, 並進行路徑壓縮
                :param p: 一個節點
                :return: 根節點
                """
                while self.parent[p] != p:
                    self.parent[p] = self.parent[self.parent[p]]
                    p = self.parent[p]
                return p
        uf, d, count, result, initial, neighbors = UF(n := len(graph)), defaultdict(int), -1, -1, sorted(initial), defaultdict(list)
        for i in range(n):
            for j in range(n):
                if graph[i][j] == 1:
                    uf.union(i, j)
        for i in range(n):
            uf.find(i)
        for i, e in enumerate(uf.parent):
            d[e] += 1
        for virus in initial:
            neighbors[uf.find(virus)].append(virus)
        for key in neighbors.keys():
            if (cost := 0 if len(neighbors[key]) > 1 else d[key]) > count:
                count, result = cost, neighbors[key][0]
        return result
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章