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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章