写在开头的话
学习了今天的基础知识,让我们来做几道题来练练手吧。如果有不懂的可以看看写在文末的思路讲解(题目是别的地方扒来的,参考答案是我自己写的,肯定不是最优解,有更好的方法欢迎评论区交流)
题目一------最长不重复子串

题目二------全部都有的子序列


题目三------最少的数


参考答案
第一题参考答案(Python版)
python
def lengthOfLongestSubstring(s: str) -> int:
char_index = {} # 记录字符最近出现的位置
left = 0 # 窗口左边界
max_len = 0
for right, ch in enumerate(s):
# 如果字符在窗口内出现过,移动左指针
if ch in char_index and char_index[ch] >= left:
left = char_index[ch] + 1
# 更新字符的最新位置
char_index[ch] = right
# 更新最大长度
max_len = max(max_len, right - left + 1)
return max_len
if __name__ == "__main__":
s = input().strip()
print(lengthOfLongestSubstring(s))
第二题参考答案(Python版)
python
def min_blue_bridge_length():
import sys
# 读取输入
n = int(sys.stdin.readline().strip())
arr = list(map(int, sys.stdin.readline().strip().split()))
# 获取所有不同的数字
unique_nums = set(arr)
total_unique = len(unique_nums)
if total_unique == 0:
return 0
left = 0
min_length = n # 初始化为最大可能长度
counter = {} # 记录当前窗口中每个数字出现的次数
found = 0 # 记录当前窗口中已经找到的不同数字数量
for right in range(n):
# 右指针向右移动,扩大窗口
num = arr[right]
counter[num] = counter.get(num, 0) + 1
# 如果是第一次遇到这个数字
if counter[num] == 1:
found += 1
# 当窗口中包含所有不同数字时,尝试缩小窗口
while found == total_unique and left <= right:
# 更新最小长度
min_length = min(min_length, right - left + 1)
# 移动左指针,缩小窗口
left_num = arr[left]
counter[left_num] -= 1
# 如果某个数字的计数变为0,说明窗口中不再包含该数字
if counter[left_num] == 0:
found -= 1
left += 1
return min_length
# 示例测试
if __name__ == "__main__":
print(min_blue_bridge_length())
第三题参考答案(Python版)
python
import sys
def main():
data = sys.stdin.read().strip().split()
if not data:
return
n, d = map(int, data[:2])
a = list(map(int, data[2:2 + n]))
# 特判:如果 d 为 1,则最小不同元素数至少为 1(除非数组为空)
if d == 1:
print(1)
return
# 使用字典记录当前窗口中每个元素的出现次数
freq = {}
unique = 0 # 当前窗口内不同元素的数量
# 初始化第一个窗口 [0, d-1]
for i in range(d):
freq[a[i]] = freq.get(a[i], 0) + 1
if freq[a[i]] == 1:
unique += 1
min_unique = unique # 记录最小值
# 滑动窗口:每次向右移动一位
for i in range(d, n):
# 移除窗口最左侧的元素 a[i-d]
left_val = a[i - d]
freq[left_val] -= 1
if freq[left_val] == 0:
unique -= 1
# 添加新元素 a[i]
right_val = a[i]
freq[right_val] = freq.get(right_val, 0) + 1
if freq[right_val] == 1:
unique += 1
# 更新最小值
if unique < min_unique:
min_unique = unique
print(min_unique)
if __name__ == "__main__":
main()
思路讲解
题目一------最长不重复子串
滑动窗口通常用两个指针(或索引)来表示当前考虑的子串的左右边界。我们用一个集合(或字典)来记录当前窗口中的字符,以保证没有重复字符。具体步骤如下:
-
初始化左指针left=0,右指针right=0,最大长度max_len=0,以及一个集合(或字典)用于记录当前窗口中的字符。
-
右指针不断向右移动,每次将右指针指向的字符加入当前窗口。如果加入后窗口中没有重复字符,则更新最大长度。
-
如果加入后窗口中出现重复字符,则移动左指针,直到窗口中没有重复字符为止。
-
重复步骤2和3,直到右指针到达字符串末尾。
题目二------全部都有的子序列
具体步骤:
-
统计所有不同的数字:使用集合获取所有不同的数字,确定目标子数组必须包含这些数字。
-
滑动窗口:
-
使用两个指针
left和right表示当前窗口的左右边界 -
使用字典
counter记录当前窗口中每个数字的出现次数 -
使用变量
found记录当前窗口中已经找到的不同数字数量
-
-
移动右指针:
-
扩大窗口,增加
counter中的计数 -
当某个数字第一次出现在窗口中时,
found加 1
-
-
移动左指针:
-
当
found == 总不同数字数时,尝试缩小窗口 -
移动左指针,减少对应数字的计数
-
如果某个数字的计数变为 0,说明窗口中不再包含该数字,
found减 1
-
-
记录最小长度:
- 每次窗口满足条件时,记录当前窗口长度,并更新最小值
题目三------最少的数
思路:我们可以用滑动窗口来统计每个长度为d的窗口内不同元素的个数,然后取最小值。
具体步骤:
-
使用一个哈希表(字典)来记录当前窗口内每个元素出现的次数。
-
初始化第一个窗口(从0到d-1)的元素计数,并统计不同元素的个数。
-
然后从索引d开始,每次移动窗口:移除窗口最左边的元素(索引i-d),加入当前元素(索引i),并更新计数和不同元素的个数。
-
如果移除后某个元素的计数变为0,则不同元素个数减1。
-
如果加入的元素之前计数为0,则不同元素个数加1。
-
-
在每次移动窗口后,记录当前窗口不同元素的数量,并更新最小值。
注意:由于n和d最大为,a[i]最大为
,所以可以用字典来计数,时间复杂度O(n),空间复杂度O(d)(存储窗口内元素计数)。
但是注意:d可能等于n,所以窗口大小最大为n。