[LeetCode周赛复盘-补] 第 300 场周赛20220710

一、本周周赛总结

  • 这周没打,补一下。

二、 [Easy] 2335. 装满杯子需要的最短总时长

链接: 2335. 装满杯子需要的最短总时长

1. 题目描述

在这里插入图片描述

2. 思路分析

定级Easy。
由于数据范围很小,减一硬做即可。

  • 由于每次操作可以搞两杯不同的水,因此优先处理多的杯子,一次处理俩。
  • 处理完了排序,重新选两个最大的。

3. 代码实现

class Solution:
    def fillCups(self, amount: List[int]) -> int:
        s = sum(amount)
        ans = 0
        while s:
            ans += 1
            amount.sort()
            amount[-1]-=1
            s-=1
            if amount[1]:
                amount[1] -= 1
                s-=1
        return ans

三、[Medium] 2336. 无限集中的最小数字

链接: 2336. 无限集中的最小数字

1. 题目描述

在这里插入图片描述

2. 思路分析

定级Medium。

  • 由于数据范围极小,1000,甚至可以把集合初始化出来。
  • 我这里用有序集合储存被删除过的但有add回来的部分,用一个min储存未被删除的部分的最小值。
  • 注意对SortedList使用in,它内部也是用二分去找的,人家不傻,详情看源码__contains__部分。
  • 如果用SortedSet的话,初始化1000更合适。

3. 代码实现

class SmallestInfiniteSet:

    def __init__(self):
        from sortedcontainers import SortedList
        self._min = 1
        self.q = SortedList()


    def popSmallest(self) -> int:
        if not self.q:
            self._min+= 1
            return self._min-1
        else :
            return self.q.pop(0)


    def addBack(self, num: int) -> None:
        if num >= self._min:
            return 
        if num not in self.q:
            self.q.add(num)

四、[Medium] 2337. 移动片段得到字符串

链接: 2337. 移动片段得到字符串

1. 题目描述

在这里插入图片描述

2. 思路分析

定级Medium。
这题不会做,看了题解。

  • 首先由于是移动产生,LR的相对位置都不能变,因此再移除两边的所有下划线后,两边的字符串应该长得一样。题目说了两个字符串长度相等,因此也不用担心下划线个数不同。
  • 使用双指针,找到每个L或者R在两个串里分别对应的位置i,j,那么:
  • 若字符是L,由于i只能左移,因此如果i<j则False.
  • 若字符是R,由于i只能右移,一次如果i>j则False。
  • 最后返回True.

3. 代码实现

class Solution:
    def canChange(self, start: str, target: str) -> bool:
        if start.replace('_','') != target.replace('_',''):
            return False
        j = 0
        for i,c in enumerate(start):
            if c == '_':
                continue
            while target[j] == '_':
                j+=1
            if i < j and c == 'L':
                return False
            if i > j and c == 'R':
                return False 
            j += 1
        return True

五、[Hard] 2338. 统计理想数组的数目

链接: 2338. 统计理想数组的数目

1. 题目描述

在这里插入图片描述

2. 思路分析

定级Hard
组合数计算+分解质因数。
完全不会做,看题解照着思路一步一步写的。

  • 我们只需要考虑长度为n的数组,不要考虑dp缩小数组规模。
  • 这个数组的元素是逐步倍增的,而这个倍非常随意,1倍、2倍、n倍都可以,只要最后一位不超过maxValue。
  • 最后一位是maxValue之间任意一个数x可以吗?可以,即使是质数,大不了就是在任意位置直接倍到x,依然有n种选择。
  • 如果不是质数,那我们考虑以这个数x为结尾的数组。注意以x为结尾,最后一个数一定要倍增到x。
  • 那么以x为结尾的数组一共有多少种情况呢?从若从1开始倍增,每次倍增的’程度’一定是x的因数,最小程度就是质因数。
  • 因此我们尝试把x做质因数分解,假设x=30,质因数分解后是2,3,5,这三个质因数谁都可以出现在n个位置任意位置上,因此用乘法原理乘起来即可,nnn。
  • 但如果质因数分解后有重复的怎么办呢,假设x=12,质因数分解后是2,2,3,对于3,当然还是出现在n个位置任意上,对于2,还这么算的话就会出现重复情况,如何计算呢?
  • 假设质因数分解后出现了k个2,那这k个2要分配到n个位置,问题转化成了一个经典问题:
    有k个相同的小球,放到n个盒子里,可以多个求放一个盒子,允许空盒,问有多少种放法。
  • 这里用插板法去做,把n个盒子看做n-1个隔板,加上k个小球看做共n-1+k个位置,选k个位置放球(或者选n-1个位置放隔板),答案是C(n-1+k,k)。
  • 那么相同的质因数用组合数计算,不同的数之间用乘法原理。
  • 其中组合数求模可以用杨辉三角递推公式或者卢卡斯定理,我用python就直接库函数了。
  • 接下来处理分解质因数并求每个质因数的个数,我这里写了个记忆化搜索:对于质数,分解质因数就是自己;否则找到最小质因数z,1个z,和除以z的商y递归结果合并。
  • 记得中途要取模,否则大数计算慢的很。

3. 代码实现

MOD = 10**9+7
primes = [1] * 10001
primes[0] =0
primes[1] =1
for i in range(2,10000):
    if primes[i]:
        for j in range(2*i,10001,i):
            primes[j] = 0

ABC = {2,3,5,7}
@cache
def get_prime_reasons(x):  # 计算x的分解质因数结果:每个质因数和它出现的次数。
    if x == 1:
        return Counter()
    if primes[x]:
        return Counter([x])
    for i in range(2,int(x**0.5)+1):
        if x % i == 0:
            return get_prime_reasons(i) + get_prime_reasons(x//i)       
    

class Solution:
    def idealArrays(self, n: int, maxValue: int) -> int:
        ans = 0
        # print(get_prime_reasons(20))
        for i in range(1,maxValue+1):
            mul = 1
            for k in get_prime_reasons(i).values():
                mul = mul* comb(n+k-1,k)%MOD
            ans = (ans+mul)%MOD

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值