[LeetCode周赛复盘] 第 300 场周赛20220710
一、本周周赛总结
- 这周没打,补一下。
二、 [Easy] 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