[英雄星球六月集训LeetCode解题日报] 第六日 滑动窗口

一、 1984. 学生分数的最小差值

链接: 1984. 学生分数的最小差值

1. 题目描述

给你一个 下标从 0 开始 的整数数组 nums ,其中 nums[i] 表示第 i 名学生的分数。另给你一个整数 k 。

从数组中选出任意 k 名学生的分数,使这 k 个分数间 最高分 和 最低分 的 差值 达到 最小化 。

返回可能的 最小差值 。

2. 思路分析

显然可以排序让离得近的分数靠一起然后滑动窗口走起。

3. 代码实现

class Solution:
    def minimumDifference(self, nums: List[int], k: int) -> int:
        n = len(nums)
        nums.sort()
        i,j = 0,k-1
        ans = nums[j]-nums[i]
        for j in range(k,n):
            i += 1
            ans = min(ans, nums[j]-nums[i])
            if ans == 0:
                return ans
        return ans

二、 1763. 最长的美好子字符串

链接: 1763. 最长的美好子字符串

1. 题目描述

当一个字符串 s 包含的每一种字母的大写和小写形式 同时 出现在 s 中,就称这个字符串 s 是 美好 字符串。比方说,“abABB” 是美好字符串,因为 ‘A’ 和 ‘a’ 同时出现了,且 ‘B’ 和 ‘b’ 也同时出现了。然而,“abA” 不是美好字符串因为 ‘b’ 出现了,而 ‘B’ 没有出现。

给你一个字符串 s ,请你返回 s 最长的 美好子字符串 。如果有多个答案,请你返回 最早 出现的一个。如果不存在美好子字符串,请你返回一个空字符串。

2. 思路分析

这题算简单就离谱,想了半天。
从大到小枚举滑窗长度,遇到美丽数组就返回。
判断美丽数组:

  1. 滑窗移动时,维护每个字母的数量 。
  2. 右侧新入字母判断是否有兄弟字符在,如果有,记录这对字符进一个set。
  3. 那么当这个set里包含所有窗口里的字符就是符合题意的情况。
  4. O(n2)

3. 代码实现

class Solution:
    def longestNiceSubstring(self, s: str) -> str:
        n = len(s)
        for k in range(n,1,-1):
            i,j = 0,k-1
            visited = set()  # 含兄弟字符的字符
            cnt = collections.defaultdict(int)  # 字符计数
            for x in range(i,k):
                c = s[x]  
                cnt[c] += 1
                d = chr(ord(c)^32)  # c的兄弟字符
                if d in cnt and cnt[d] > 0:
                    visited.add(c)
                    visited.add(d) 
            if len(visited) == len(cnt):
                return s[i:j+1]
            # print(k,cnt,visited)
            for j in range(k,n):
                # 滑窗右移,删除左边一个元素
                c = s[i]
                cnt[c] -= 1
                if cnt[c] == 0 :
                    visited.discard(c)
                    visited.discard(chr(ord(c)^32))
                    del cnt[c]
                i += 1
                # 增加右边一个元素
                c = s[j]
                d = chr(ord(c)^32) 
                cnt[c] += 1
                if d in cnt and cnt[d] > 0:
                    visited.add(c)
                    visited.add(d)
                if len(visited) == len(cnt):
                    return s[i:j+1]
                    
                # print(k,cnt,visited)
                

        return ''
                

三、 2269. 找到一个数字的 K 美丽值

链接: 2269. 找到一个数字的 K 美丽值

1. 题目描述

一个整数 num 的 k 美丽值定义为 num 中符合以下条件的 子字符串 数目:

子字符串长度为 k 。
子字符串能整除 num 。
给你整数 num 和 k ,请你返回 num 的 k 美丽值。

注意:

允许有 前缀 0 。
0 不能整除任何值。
一个 子字符串 是一个字符串里的连续一段字符序列。

2. 思路分析

直接模拟。

3. 代码实现

class Solution:
    def divisorSubstrings(self, num: int, k: int) -> int:
        s = str(num)
        ans = 0
        for j in range(k-1,len(s)):
            a = int(s[j-k+1:j+1])
            if a>0 and num%a==0:
                ans += 1
        return ans

四、995. K 连续位的最小翻转次数

链接: 995. K 连续位的最小翻转次数

1. 题目描述

给定一个二进制数组 nums 和一个整数 k 。

k位翻转 就是从 nums 中选择一个长度为 k 的 子数组 ,同时把子数组中的每一个 0 都改成 1 ,把子数组中的每一个 1 都改成 0 。

返回数组中不存在 0 所需的最小 k位翻转 次数。如果不可能,则返回 -1 。

子数组 是数组的 连续 部分。

2. 思路分析

困难题。
参考: [LeetCode解题报告] 995. K 连续位的最小翻转次数
用队列维护前边窗口翻转的左端点,那么可以通过队列长度来判断自己现在的值。
或者用区间更新单点询问的模型也能做。

3. 代码实现

class Solution:
    def minKBitFlips(self, nums: List[int], k: int) -> int:      
        n = len(nums)
        q = deque()
        ans = 0
        for i in range(n-k+1):
            if q and q[0] <= i-k:
                q.popleft()
            if nums[i] ^ (len(q)&1) == 1:
                continue
            ans += 1
            q.append(i)

        for i in range(n-k+1,n):
            if q and q[0] <= i-k:
                q.popleft()
            if nums[i] ^ (len(q)&1) == 0:
                return -1
        return ans

五、参考链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值