You have n gardens, labeled from 1 to n, and an array paths where paths[i] = [xi, yi] describes a bidirectional path between garden xi to garden yi. In each garden, you want to plant one of 4 types of flowers.

All gardens have at most 3 paths coming into or leaving it.

Your task is to choose a flower type for each garden such that, for any two gardens connected by a path, they have different types of flowers.

Return any such a choice as an array answer, where answer[i] is the type of flower planted in the (i+1)th garden. The flower types are denoted 1, 2, 3, or 4. It is guaranteed an answer exists.

Example 1:

Input: n = 3, paths = [[1,2],[2,3],[3,1]]
Output: [1,2,3]
Explanation:
Gardens 1 and 2 have different types.
Gardens 2 and 3 have different types.
Gardens 3 and 1 have different types.
Hence, [1,2,3] is a valid answer. Other valid answers include [1,2,4], [1,4,2], and [3,2,1].

Example 2:

Input: n = 4, paths = [[1,2],[3,4]]
Output: [1,2,1,2]

Example 3:

Input: n = 4, paths = [[1,2],[2,3],[3,4],[4,1],[1,3],[2,4]]
Output: [1,2,3,4]

Constraints:

  • 1 <= n <= 10^4
  • 0 <= paths.length <= 2 * 10^4
  • paths[i].length == 2
  • 1 <= xi, yi <= n
  • xi != yi
  • Every garden has at most 3 paths coming into or leaving it.

题意:有 n 个花园,按从 1n 标记。另有数组 paths ,其中 paths[i] = [xi, yi] 描述了花园 xi 到花园 yi 的双向路径。在每个花园中,你打算种下四种花之一。另外,所有花园 最多3 条路径可以进入或离开。需要为每个花园选择一种花,使得通过路径相连的任何两个花园中的花的种类互不相同。

以数组形式返回 任一 可行的方案作为答案 answer ,其中 answer[i] 为在第 (i+1) 个花园中种植的花的种类。花的种类用 1、2、3、4 表示。保证存在答案。


解法 模拟+暴力

出题人可能是受到四色定理的启发出的题。问题相当于用 4 4 4 种颜色给图中的每个节点染色,要求相邻节点颜色不同。而「所有花园最多有 3 3 3 条路径可以进入或离开」,这相当于图中每个点的度数至多为 3 3 3 ,那么只要选一个和邻居不同的颜色即可

哈希表(数组)实现:

class Solution { 
public:
    vector<int> gardenNoAdj(int n, vector<vector<int>>& paths) {
        vector<vector<int>> g(n);
        vector<int> ans(n);
        for (vector<int> &v : paths) {
            g[v[0] - 1].push_back(v[1] - 1); // 从0开始
            g[v[1] - 1].push_back(v[0] - 1);
        } 
        for (int i = 0; i < n; ++i) { // 给结点i选择颜色
            bool used[5]{};
            for (int j: g[i]) used[ans[j]] = true;
            while (used[++ans[i]]) ;
        }
        return ans;
    }
}; 

位运算实现: 我们需要找到 u s e d used used 从低到高第一个 0 0 0 的位置,即第一个未使用的颜色,这需要我们计算 u s e d used used 取反后的尾零个数。例如 used = 1011 1 ( 2 ) \textit{used}=10111_{(2)} used=10111(2) ​,取反后变为 100 0 ( 2 ) 1000_{(2)} 1000(2) (实际前导零也取反了,但不影响计算),尾零个数为 3 3 3 ,这恰好就是从低位到高位第一个 0 0 0 的位置。

class Solution { 
public:
    vector<int> gardenNoAdj(int n, vector<vector<int>>& paths) {
        vector<vector<int>> g(n);
        vector<int> ans(n);
        for (vector<int> &v : paths) {
            g[v[0] - 1].push_back(v[1] - 1); // 从0开始
            g[v[1] - 1].push_back(v[0] - 1);
        } 
        for (int i = 0; i < n; ++i) { // 给结点i选择颜色
            int used = 1; // 由于颜色是1~4,把0加入mask保证下面不会算出0
            for (int j: g[i]) used |= 1 << ans[j];
            ans[i] = __builtin_ctz(~used);
        }
        return ans;
    }
}; 

复杂度分析:

  • 时间复杂度: O ( n + m ) O(n+m) O(n+m) ,其中 m m m p a t h s paths paths 的长度。
  • 空间复杂度: O ( n + m ) O(n+m) O(n+m)
04-16 18:22