• [LeetCode85双周赛] [滑动窗口] [差分数组] [并查集]


    LeetCode 6156. 得到 K 个黑块的最少涂色次数

    https://leetcode.cn/problems/minimum-recolors-to-get-k-consecutive-black-blocks/

    暴力法

    每次找连续为 k k k 的连续块,然后求其中每 k k k 个块中白色块最少个数。
    时间复杂度: O ( n 2 ) O(n^2) O(n2)

    class Solution:
        def minimumRecolors(self, blocks: str, k: int) -> int:
            n = len(blocks)
            ans = n
            for i in range(n - k + 1):
                count = 0
                for j in range(i, i + k):
                    if blocks[j] == 'W':
                        count += 1
                ans = min(ans, count)
            return ans
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    滑动窗口

    定义一个 k k k 长度的窗口,向后滑动,若要离开窗口位置为白块,cnt--,若要加入窗口位置为白块,cnt++
    时间复杂度: O ( n ) O(n) O(n)

    class Solution:
        def minimumRecolors(self, blocks: str, k: int) -> int:
            cnt = blocks[:k].count('W')
            ans = cnt
            for i in range(len(blocks) - k):
                cnt += -(blocks[i] == 'W') + (blocks[i+k] == 'W')
                ans = min(ans, cnt)
            return ans
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    LeetCode 6157. 二进制字符串重新安排顺序需要的时间

    https://leetcode.cn/problems/time-needed-to-rearrange-a-binary-string/

    模拟(调用 API)

    class Solution:
        def secondsToRemoveOccurrences(self, s: str) -> int:
            ans = 0
            while '01' in s:
                s = s.replace('01', '10')
                ans += 1
            return ans
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    动态规划

    我们的目的是让所有的 1 都到左面,所有的 0 都到右遍变为类似 11100000 的形式。

    • 每个 1 前面 0 的个数表示 1 若要到对应位置所需最少的秒数
    • 如果至少有两个连续的 1 出现表示后面的 1 需要等待前面的 1 移动后才能进行移动。
    class Solution:
        def secondsToRemoveOccurrences(self, s: str) -> int:
            f = pre0 = 0
            for c in s:
                if c == '0':
                    pre0 += 1
                # '1' 前面有 '0' 才计算,没 '0' 表示已经到目标位置了,不用管
                elif pre0 > 0: 
                    f = max(f + 1, pre0) 
            return f
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    LeetCode 6158. 字母移位 II

    https://leetcode.cn/problems/shifting-letters-ii/
    这题暴力做会超时,用差分数组会降到线性。差分数组求前缀和即为各个区间的最终变化结果

    ★差分数组

    差分数组可以把一个区间操作变为对两个数的操作,从而节省时间。

    class Solution:
        def shiftingLetters(self, s: str, shifts: List[List[int]]) -> str:
            diff = [0] * (len(s) + 1)
            for start, end, op in shifts:
                op = 2 * op - 1 # 取代 if op == 0: op = -1
                diff[start] += op
                diff[end+1] -= op
    
            # 计算差分数组前缀和,表示求得数组根据所给的区间求得的最后的变化
            for i in range(1, len(s)):
                diff[i] += diff[i-1]
            
            # 生成字符对索引的映射, ascii_lowercase 是 string 模块的内置变量,官方已经引入
            ascii_dct = {c : i for i, c in enumerate(ascii_lowercase)}
    
            ans = []
            for c, dif in zip(s, diff):
                ans.append(ascii_lowercase[(ascii_dct[c] + dif) % 26])
            
            return ''.join(ans)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    补充类似题目(差分数组) LeetCode 1450. 在既定时间做作业的学生人数

    https://leetcode.cn/problems/number-of-students-doing-homework-at-a-given-time/

    class Solution:
        def busyStudent(self, startTime: List[int], endTime: List[int], queryTime: int) -> int:
            maxEndTime = max(endTime)
            if queryTime > maxEndTime:
                return 0
    
            cnt = [0] * (maxEndTime + 2)
            for s, e in zip(startTime, endTime):
                cnt[s] += 1
                cnt[e + 1] -= 1
                
            res = []
            s = 0
            # 对差分数组求前缀和即为各个区间的最终变化结果
            for x in cnt:
                s += x
                res.append(s)
            return res[queryTime]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    LeetCode 6159. 删除操作后的最大子段和

    https://leetcode.cn/problems/maximum-segment-sum-after-removals/
    正序为删除节点,求两边元素和。转换其为倒序,合并两边的元素。

    倒序★并查集

    灵神版:

    class Solution:
        def maximumSegmentSum(self, nums: List[int], removeQueries: List[int]) -> List[int]:
            # 并查集     
            def find(x):
                if fa[x] != x:
                    fa[x] = find(fa[x]) 
                return fa[x]
                
            n = len(nums)
            ans = [0] * n
            s = [0] * (n + 1)
            fa = list(range(n + 1))
            
            # 因为最后删除全部元素结果为 0,故不需要考虑
            for i in range(n-1, 0, -1):
                x = removeQueries[i]
                to = find(x + 1)
                fa[x] = to  # 合并 x 和 x+1
                s[to] += s[x] + nums[x]
                ans[i - 1] = max(ans[i], s[to])
            return ans
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    Y总版:

    class Solution:
        def maximumSegmentSum(self, nums: List[int], removeQueries: List[int]) -> List[int]:
            # 并查集
            def find(x):
                if fa[x] != x:
                    fa[x] = find(fa[x]) 
                return fa[x]
            
            #初始化
            n = len(nums)
            ans = []
            s = [0] * n 
            fa = list(range(n))
            maxs = 0
    
            # 因为最后删除全部元素结果为 0,故不需要考虑
            for i in range(n-1, -1, -1):
                x = removeQueries[i] 
                s[x] = nums[x]
                for j in [x-1, x+1]:
                    # s[j] > 0 表示已经被加入过,该集合存在
                    # 将合并 x-1 和 x+1 合并到 x
                    if j >= 0 and j < n and s[j] > 0:
                        to = find(j)
                        s[x] += s[to]
                        fa[to] = x
                ans.append(maxs)
                maxs = max(maxs, s[x])
            return ans[::-1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    宫水三叶姐的 Github

    https://github.com/SharingSource/LogicStack-LeetCode/wiki

  • 相关阅读:
    Flyway Desktop updated
    文本嵌入层
    ubuntu-server部署hive-part1-安装jdk
    Cookie、Session、Token三者的区别
    容器内存溢出排障思路
    flutter开发实战-video_player播放多个视频MediaCodecVideoRenderer error问题
    c#输入和输出
    JavaScript作用域和预解析
    CUDA小白 - NPP(6) 图像处理 Geometry Transforms (1)
    AJAX 简介
  • 原文地址:https://blog.csdn.net/qq_39906884/article/details/126446396