[LeetCode周赛复盘] 第 374 场周赛20231203

[LeetCode周赛复盘] 第 374 场周赛20231203

    • 一、本周周赛总结
    • 100144. 找出峰值
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 100153. 需要添加的硬币的最小数量
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 100145. 统计完全子字符串
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 100146. 统计感冒序列的数目
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 参考链接

一、本周周赛总结

  • 比赛后才做出T3,没敢交
  • T1 模拟。
  • T2 贪心+分类讨论。
  • T3 26维前缀和+枚举。
  • T4 组合数学。

100144. 找出峰值

100144. 找出峰值

1. 题目描述

[LeetCode周赛复盘] 第 374 场周赛20231203_第1张图片

2. 思路分析

按题意模拟即可。

3. 代码实现

class Solution:
    def findPeaks(self, a: List[int]) -> List[int]:
        return [i for i in range(1,len(a)-1) if a[i-1] < a[i] > a[i+1]]

100153. 需要添加的硬币的最小数量

100153. 需要添加的硬币的最小数量

1. 题目描述

[LeetCode周赛复盘] 第 374 场周赛20231203_第2张图片

2. 思路分析

分类讨论
  • 先把数据排序,从小到大处理。
  • 假设当前我们已经得到了[0,s)之间所有的整数。下一个要添加的数x。
    • 添加后可以新获得[x,x+s)之间所有的数。
  • 若x<=s,则可以获得[0,x+s)。
  • 若x>s, 则无法得到s,必须添加s,得到[0,s+s)。

  • 时间复杂度O(nlgn+lgtarget),
  • 解释其中lgtarget:若coins为空,那么我们必须自己构造1 2 4 8相当于给target二进制分解。

3. 代码实现

class Solution:
    def minimumAddedCoins(self, coins: List[int], target: int) -> int:
        coins.sort()
        n = len(coins)
        ans = 0 
        i = 0
        s = 1
        while s <= target:
            if i < n and coins[i] <= s:
                s += coins[i]
                i += 1
            else:
                s += s 
                ans += 1
        return ans

100145. 统计完全子字符串

100145. 统计完全子字符串

1. 题目描述

[LeetCode周赛复盘] 第 374 场周赛20231203_第3张图片

2. 思路分析

 被这题干趴了。一开始写了个滑窗一直wa。
  • 这题的难点主要在于计算复杂度,敢不敢暴力。
  • 观察合法子串性质,发现子串长度一定是k的倍数,而且最多是26k。再大的话,一定有字母的出现次数超过k了。
  • 枚举每个位置作为子串的最后一个字符,左端点每次向前跳k,能否快速计算这段里的每个字符的出现次数?
    • 对每个字符单独做前缀和,用一个26*(n+1)的数组存。
    • 这样计算的次数是26。
  • 另外注意,相邻字符差不能超过2,因此左端点向前跳时不能超过这段的开头。
  • 实现时,把原串先改写成0~25的数字。

  • 时间复杂度O(n2626)。最多比较26次(向前跳),每次比较花费26。

3. 代码实现

class Solution:
    def countCompleteSubstrings(self, word: str, k: int) -> int:
        n = len(word)
        a = [ord(c) - ord('a') for c in word]
        cnt = [[0] * 26 for _ in range(n+1)]
        for i, v in enumerate(a):
            cnt[i+1] = cnt[i][:]
            cnt[i+1][v] += 1
        ans = 0
        start = 0  # 当前连续段的开头(相邻差<=2)
        for i, v in enumerate(a):
            if i and abs(v-a[i-1]) > 2:  # 重开一段
                start = i 
            j = i - k + 1  # 往前跳
            over_k = False  # 有一个字符数量已经超过k
            while j >= start and not over_k:
                for x,y in zip(cnt[i+1],cnt[j]):
                    if x-y>k:
                        over_k = True 
                        break
                    if x-y > 0 and x - y != k :
                        break
                else:
                    ans += 1
                j -= k
        
        return ans 

100146. 统计感冒序列的数目

100146. 统计感冒序列的数目

1. 题目描述

[LeetCode周赛复盘] 第 374 场周赛20231203_第4张图片

2. 思路分析

组合数学
  • m = len(sick)个病人把 整个数组分割成m+1段,只讨论不为空的段。
  • 处于中间的段,长为k,自己的传染顺序方案有pow(2,k-1)种,即每次要么感染左端,要么感染右端,当长为1时,左右等价。
  • 一共n-m个健康人,从这个序列中选k个位置,作为这组的人的位置,共C(n-m,k)种方案。
    • 安排完这一组,安排下一组时,是从n-m-k中选k’个位置。
  • 然后讨论处于两端的段,他们只有一个传染方向,因此自己的顺序只有一种,但要讨论位置方案。

  • 其中组合数直接贴逆元模板。
  • 初始化放里边竟然会TLE,难绷

3. 代码实现

class ModComb:
    """通过O(n)预处理逆元,达到O(1)询问组合数"""
    def __init__(self, n, p):
        """
        初始化,为了防止模不一样,因此不写默认值,强制要求调用者明示
        :param n:最大值
        :param p: 模
        """
        self.p = p
        self.inv_f, self.fact = [1] * (n + 1), [1] * (n + 1)
        inv_f, fact = self.inv_f, self.fact
        for i in range(2, n + 1):
            fact[i] = i * fact[i - 1] % p
        inv_f[-1] = pow(fact[-1], p - 2, p)
        for i in range(n, 0, -1):
            inv_f[i - 1] = i * inv_f[i] % p

    def comb(self, m, r):
        if m < r or r < 0:
            return 0
        return self.fact[m] * self.inv_f[r] % self.p * self.inv_f[m - r] % self.p
MOD = 10 ** 9 + 7 
mc = ModComb(10**5 + 5, MOD)
class Solution:
    def numberOfSequence(self, n: int, sick: List[int]) -> int:
        ans = 1 
        s = n - len(sick)
        for x,y in pairwise(sick):
            v = y - x -1
            if v:
                ans = ans * mc.comb(s,v) % MOD * pow(2,v-1,MOD) % MOD 
                s -= v 
        ans = ans * mc.comb(s,sick[0]) % MOD
        return ans % MOD       

参考链接

你可能感兴趣的:(力扣周赛复盘,leetcode,算法,职场和发展)