[LeetCode周赛复盘] 第 115 场双周赛20231014

[LeetCode周赛复盘] 第 115 场双周赛20231014

    • 一、本周周赛总结
    • 100095. 上一个遍历的整数
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 100078. 最长相邻不相等子序列 I
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 100077. 最长相邻不相等子序列 II
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 100029. 和带限制的子多重集合的数目
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 参考链接

一、本周周赛总结

  • T1 模拟。
  • T2 贪心。
  • T3 DP类似LIS,构造路径方案。
  • T4 分组前缀和优化的分组背包求方案数。
    [LeetCode周赛复盘] 第 115 场双周赛20231014_第1张图片

100095. 上一个遍历的整数

100095. 上一个遍历的整数

1. 题目描述

[LeetCode周赛复盘] 第 115 场双周赛20231014_第2张图片

2. 思路分析

按题意模拟即可。

3. 代码实现

class Solution:
    def lastVisitedIntegers(self, words: List[str]) -> List[int]:
        ans = []
        nums = []
        k=0
        for v in words:
            if v[0].isdigit():
                nums.append(int(v))
                k = 0 
            else:
                k += 1 
                if k > len(nums):
                    ans.append(-1)
                else:
                    ans.append(nums[-k])
        return ans 

100078. 最长相邻不相等子序列 I

100078. 最长相邻不相等子序列 I

1. 题目描述

[LeetCode周赛复盘] 第 115 场双周赛20231014_第3张图片

2. 思路分析

方法1
  • 枚举第一个g是0还是1,然后贪心的向后取位置。

方法2
  • 直接pairwise,相邻不同了,则可以取左边的,注意记得取最后一个。

3. 代码实现

class Solution:
    def getWordsInLongestSubsequence(self, n: int, words: List[str], groups: List[int]) -> List[str]:

        def f(s):
            ans = [0,[]]
            for w, g in zip(words,groups):
                if g == s:
                    ans[0]+=1
                    ans[1].append(w)
                    s ^= 1 
            return ans
       
        return max(f(0),f(1))[1]

100077. 最长相邻不相等子序列 II

100077. 最长相邻不相等子序列 II

1. 题目描述

[LeetCode周赛复盘] 第 115 场双周赛20231014_第4张图片

2. 思路分析

  • n方dp。
  • 从前边满足的地方转移过来,注意记录一个from_index来储存路径。

3. 代码实现

def han(s, t):
    return sum(x!=y for x,y in zip(s,t))
class Solution:
    def getWordsInLongestSubsequence(self, n: int, words: List[str], groups: List[int]) -> List[str]:
        f = [1]*n 
        from_index = [-1]*n
        for i, (w, g) in enumerate(zip(words,groups)):
            for j in range(i):
                if g != groups[j] and len(w) == len(words[j]) and han(words[j], w) == 1 and f[j] >= f[i]:
                    f[i] = f[j] + 1
                    from_index[i] = j
        i = f.index(max(f))
        ans = []
        while i != -1:
            ans.append(words[i])
            i = from_index[i]
        return ans[::-1]                    

100029. 和带限制的子多重集合的数目

100029. 和带限制的子多重集合的数目

1. 题目描述

[LeetCode周赛复盘] 第 115 场双周赛20231014_第5张图片

2. 思路分析

  • 题目描述很复杂,但其实是分组背包求方案数。
  • 这样的话,值域是2e4,物品数也是2e4。n方会TLE。
  • 考虑优化,我们知道分组背包先遍历组,然后遍历体积,再遍历每组里的物品。
    • 可以看到内层,f[j] += f[j-k]+…f[j-k*c],这里累计了1~c,并且间隔是一样的,考虑用前缀和优化。
    • 可以用分组前缀和,类似滑窗。参考普通前缀和,我们向前边添加k个0,方便代码。
  • 注意到,题目限制sum(nums)<=2e4,那么不同的数字最多有多少组呢?显然最小是1,2,3~,那么不同数字组最多是开方级别的。
  • 因此复杂度变成了O(r√S)。

3. 代码实现

MOD = 10**9 + 7 
class Solution:
    def countSubMultisets(self, nums: List[int], l: int, r: int) -> int:
        cnt = Counter(nums)
        f = [cnt[0]+1] + [0] * r
        s = 0
        for k, c in cnt.items():
            if k == 0:continue
            s += k * c 
            pre = [0]*k             
            for v in f:
                pre.append((v+pre[-k])%MOD)
            for j in range(min(s, r), 0, -1):
                # f[j] += f[j-k]+..f[j-k*c]
                f[j] += pre[j] - pre[max(j-k*c, 0)]
                f[j] %= MOD 
        return sum(f[l:]) %MOD   

参考链接

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