日渐头秃的代码日记 -- 第363场周赛 第2题 让所有学生保持开心的分组方法数

87 阅读1分钟

题目:让所有学生保持开心的分组方法数

给你一个下标从 0 开始、长度为 n 的整数数组 nums ,其中 n 是班级中学生的总数。班主任希望能够在让所有学生保持开心的情况下选出一组学生:

如果能够满足下述两个条件之一,则认为第 i 位学生将会保持开心:

  • 这位学生被选中,并且被选中的学生人数 严格大于 nums[i] 。
  • 这位学生没有被选中,并且被选中的学生人数 严格小于 nums[i] 。

返回能够满足让所有学生保持开心的分组方法的数目。

 

示例 1:

输入: nums = [1,1]
输出: 2
解释:
有两种可行的方法:
班主任没有选中学生。
班主任选中所有学生形成一组。 
如果班主任仅选中一个学生来完成分组,那么两个学生都无法保持开心。因此,仅存在两种可行的方法。

示例 2:

输入: nums = [6,0,3,3,6,7,2,7]
输出: 3
解释:
存在三种可行的方法:
班主任选中下标为 1 的学生形成一组。
班主任选中下标为 1、2、3、6 的学生形成一组。
班主任选中所有学生形成一组。 

 

提示:

  • 1 <= nums.length <= 105
  • 0 <= nums[i] < nums.length

解析

让所有学生都开心了,感觉我们做题的人不是很开心啊(doge)

需要找到所有子数组的组合方式,使得选中的子数组里每一个数字都小于子数组的长度,没有被选中的数字都大于子数组的长度。暴力求解必然会超时。

根据第二个示例发现,选中下标为1/2/3/6的学生的时候,数字刚好是nums里偏小的这一部分,提供了思路,可以先把nums排序一次,这样重排之后的下标+1这个值(因为下标是从0开始)就表示选中了哪些人。而只要下标对应的num数字 小于 下标+1 小于num后边的那个数字,就是符合条件的一个解。

代码

class Solution:
    def countWays(self, nums: List[int]) -> int:
        count = 0
        nums = sorted(nums)
        for index, v in enumerate(nums):
            if index < len(nums) - 1:
                if index + 1 > v and index + 1 < nums[index+1]:
                    count += 1
            else:
                if index + 1 > v and index + 1:
                    count += 1
        
        if nums[0] > 0:
            count += 1
        return count

image.png

这里代码写得清晰明了一些,也可以使用itertools.pairwise来简化一下。