图解LeetCode——1282. 用户分组(难度:中等)

一、题目

有 n 个人被分成数量未知的组。每个人都被标记为一个从 0 到 n - 1 的 唯一ID 。

给定一个整数数组 groupSizes ,其中 groupSizes[i] 是第 i 个人所在的组的大小。例如,如果 groupSizes[1] = 3 ,则第 1 个人必须位于大小为 3 的组中。

返回一个组列表,使每个人 i 都在一个大小为 groupSizes[i] 的组中。

每个人应该 恰好只 出现在 一个组 中,并且每个人必须在一个组中。如果有多个答案,返回其中 任何 一个。可以 保证 给定输入 至少有一个 有效的解。

二、示例

2.1> 示例 1:

【输入】groupSizes = [3,3,3,3,3,1,3]
【输出】[[5],[0,1,2],[3,4,6]]
【解释】
第一组是 [5],大小为 1,groupSizes[5] = 1。
第二组是 [0,1,2],大小为 3,groupSizes[0] = groupSizes[1] = groupSizes[2] = 3。
第三组是 [3,4,6],大小为 3,groupSizes[3] = groupSizes[4] = groupSizes[6] = 3。
其他可能的解决方案有 [[2,1,6],[5],[0,4,3]] 和 [[5],[0,6,2],[4,3,1]]。

2.2> 示例 2:

【输入】groupSizes = [2,1,3,3,3,2]
【输出】[[1],[0,5],[2,3,4]]

提示:

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

三、解题思路

3.1> 思路1:哈希表 + 取余分组

根据题目表述,我们会获得一个数组groupSizes,该数组中的下标index表示的是某个人的唯一标识,大家可以把它当做是userId;那么数组中对应的元素值,即:groupSIzes[userId],表示的就是这个User所在的数组的长度值。也就是说,如果userId等于3(index=3),它对应的数组中元素值为2(groupSIzes[2]),那么说明userId等于3的这个人,应该存在于一个数组长度等于2的数组中。

既然了解明白了题意,我们在思路一种,首先想到的是,要把原有的数组groupSizes中的每个元素,进行一个迁移操作。那迁移到哪里去会比较好呢?因为这里面涉及到userId与所在数组长度的对应关系,所以,我们第一个想到的就应该是迁移到Map结构中,Map中的key保存数组长度,value保存userId。那么以groupSizes=[3,3,3,3,3,1,3]为例,当迁移到map结构中以后,对应的key=1,value=[5];key=3,value=[0,1,2,3,4,6]。

那么,在后续的操作,跟我们打交道的就是这个map了。我们通过获得map中的每一个Entry对象,从而循环进行遍历操作。比如,我们获得map中的第一个Entry对象,它的key等于1,value等于[5]。那么我们就可以创建一个长度为1的ArrayList集合,然后将元素5放入其中。

当我们获得第二个Entry对象的时候,key等于3,value等于[0,1,2,3,4,6],在这种情况下,我们就面临着要拆分集合操作了。怎么拆分呢?这里我们通过value中元素的index与数组size取余,如果发现结果等于0了,就说明该执行拆分了。以上面的第二个Entry为例,key等于3,所以长度size也就等于3,那么,index等于0、1、2的时候,与3取余都不为0,只有当index=3的时候,与3取余等于0,所以,index等于3、4、5的时候,是放入另外一个集合中的。具体操作,如下图所示:

确定了解题思路,代码实现就比较简单了。具体代码实现,请参见4.2> 实现1:哈希表 + 取余分组

3.2> 思路2:哈希表 + 长度判断

其实我们仔细分析题意,我们会发现,元素的个数与数组长度是相匹配的。什么意思呢?我们还是以groupSizes=[3,3,3,3,3,1,3]为例,我们发现,最终结果里,分组长度为3的一共有两组,分别是[0,1,2]和[3,4,6],长度为3的集合里,存储了正好3个元素,那可不可以只存储2个元素呢?也就是说,如果入参是groupSizes=[3,3,3,1,3]的时候,不就满足了长度为3的两个集合中,一个存储了[0,1,2],另外一个存储了[4]嘛。 那是,其实在题目中的约束里,是不允许的。比如,我们修改一下测试用例,就会给我们如下的提示:

那么既然分组中都会填满元素,那么我们就可以有另外一种更便捷的解题思路了。也就是说,我们将groupSizes数组转换为Map这一步骤没有变化,但是呢,每当从groupSizes中获取一个元素,然后添加到Map的时候,我们都要判断一下,此时的value中的size是不是等于了key值,如果等于,说明value中存储的元素已经可以作为一个分组放入的最终结果的result集合中了,那么通过调用Map的remove()方法将数据迁移到result中。这种方式代码量会减少很多,而且执行效率也比较高。具体操作,如下图所示:

关于思路2中的代码实现,请参见4.2> 实现2:哈希表 + 长度判断

四、代码实现

4.1> 实现1:哈希表 + 取余分组

class Solution {
    public List<List<Integer>> groupThePeople(int[] groupSizes) {
        Map<Integer, List<Integer>> map = new HashMap();
        for (int i = 0; i < groupSizes.length; i++) {
            int size = groupSizes[i];
            if (map.get(size) == null) map.put(size, new ArrayList<>());
            map.get(size).add(i);
        }

        int index = -1;
        List<List<Integer>> result = new ArrayList(map.size());
        for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
            Integer size = entry.getKey();
            List<Integer> list = entry.getValue();
            int num = 0;
            for (Integer id : list) {
                if (num % size == 0) {
                    result.add(new ArrayList(size));
                    index++;
                }
                result.get(index).add(id);
                num++;
            }
        }

        return result;
    }
}

4.2> 实现2:哈希表 + 长度判断

class Solution {
    public List<List<Integer>> groupThePeople(int[] groupSizes) {
        List<List<Integer>> ans = new ArrayList<>();

        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < groupSizes.length; i++) {
            map.computeIfAbsent(groupSizes[i], k -> new ArrayList<>()).add(i);
            if (groupSizes[i] == map.get(groupSizes[i]).size()) {
                ans.add(map.remove(groupSizes[i]));
            }
        }

        return ans;
    }
}

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值