[LeetCode] 1282. Group the People Given the Group Size They Belong To 用户分组


There are n people that are split into some unknown number of groups. Each person is labeled with a unique ID from 0 to n - 1.

You are given an integer array groupSizes, where groupSizes[i] is the size of the group that person i is in. For example, if groupSizes[1] = 3, then person 1 must be in a group of size 3.

Return a list of groups such that each person i is in a group of size groupSizes[i].

Each person should appear in exactly one group, and every person must be in a group. If there are multiple answers, return any of them. It is guaranteed that there will be at least one valid solution for the given input.

Example 1:

Input: groupSizes = [3,3,3,3,3,1,3]
Output: [[5],[0,1,2],[3,4,6]]
Explanation:
The first group is [5]. The size is 1, and groupSizes[5] = 1.
The second group is [0,1,2]. The size is 3, and groupSizes[0] = groupSizes[1] = groupSizes[2] = 3.
The third group is [3,4,6]. The size is 3, and groupSizes[3] = groupSizes[4] = groupSizes[6] = 3.
Other possible solutions are [[2,1,6],[5],[0,4,3]] and [[5],[0,6,2],[4,3,1]].

Example 2:

Input: groupSizes = [2,1,3,3,3,2]
Output: [[1],[0,5],[2,3,4]]

Constraints:

  • groupSizes.length == n
  • 1 <= n <= 500
  • 1 <= groupSizes[i] <= n

这道题说是将n个人(编号为0到 n-1)分为若干个组,现在给了一个 groupSizes 数组,其中 groupSizes[i] 是编号为i的人所在的组的总人数,现在让返回分成的这些组,并将该组的人的编号放进去。通过分析例子不难理解题意,例子1中,一堆3中间有一个有一个1,其位置是5,那么很显然,编号为5的人,单独是一组,那么博主就想到,应该是先处理人数少的组,则可以对总人数排序,但是由于编号信息不能丢失,所以可以建立组人数和编号的 pair 对儿,然后放到一个新数组 all 中,然后对 all 进行排序,默认是以 pair 对儿中的第一个元素为 key 进行排序,即是按照组人数从小到大排序。这样就可以开始处理了,取出当前的组人数 cnt,然后新建一个数组 out,变量j从0遍历到 cnt,然后将 all[i+j][1] 加入数组 out 中,即把对应的编号加入。因为组人数是有序的,所以若当前是 cnt,则之后 cnt 个数字一定都等于 cnt,所以可以按顺序加入到 out 数组中,然后将 out 加入结果 res,此时要更新变量i,将其加上 cnt-1,因为 for 循环本身还要再加1,参见代码如下:


解法一:

class Solution {
public:
    vector<vector<int>> groupThePeople(vector<int>& groupSizes) {
        vector<vector<int>> res, all;
        int n = groupSizes.size();
        for (int i = 0; i < n; ++i) {
            all.push_back({groupSizes[i], i});
        }
        sort(all.begin(), all.end());
        for (int i = 0; i < n; ++i) {
            int cnt = all[i][0];
            vector<int> out;
            for (int j = 0; j < cnt; ++j) {
                out.push_back(all[i + j][1]);
            }
            res.push_back(out);
            i += cnt - 1;
        }
        return res;
    }
};

上面的方法虽然 work,但也是险过,说不定哪天就被 OJ 排除在外了,这道题其实有更简单高效的解法。并不需要排序,而是将所在群组人数相同的人归类到一起,这样可以使用一个二维数组 all,其中 all[i] 表示所在群组个数为i的人的编号的集合,大小初始化为 n+1,其中n是 groupSizes 的大小。然后i从0遍历到 n-1,将编号i放入 all[groupSizes[i]] 中,因为 groupSizes[i] 是编号为i的人所在的群组的人数,外面套个 all,就是具有相同群组人数的人的集合,若等于 groupSizes[i],说明此时的群组已经放满了,可以加入到结果 res 中,然后将其清空,以便给放之后符合条件的人,参见代码如下:


解法二:

class Solution {
public:
    vector<vector<int>> groupThePeople(vector<int>& groupSizes) {
        int n = groupSizes.size();
        vector<vector<int>> res, all(n + 1);
        for (int i = 0; i < n; ++i) {
            all[groupSizes[i]].push_back(i);
            if (all[groupSizes[i]].size() == groupSizes[i]) {
                res.push_back(all[groupSizes[i]]);
                all[groupSizes[i]].clear();
            }
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1282


参考资料:

https://leetcode.com/problems/group-the-people-given-the-group-size-they-belong-to/

https://leetcode.com/problems/group-the-people-given-the-group-size-they-belong-to/discuss/446534/C%2B%2BJava-Greedy


LeetCode All in One 题目讲解汇总(持续更新中...)

上一篇:2022.1.14


下一篇:LeetCode-76. 最小覆盖子串