滑动窗口之字符串重复不超过k
给一串字符串,分割字符串以后,字符串前缀和后缀拼接后组成str,要求str中重复字符的个数不能大于k。
如“abcab”,a|b|cab str="acab",要求分割出去的字符串长度len, 1≤len≤n-1,也就是说最好删除一个,最多删除n-1个
输入n表示字符串长度,k 表示不得大于的重复数字
输入
5 1
abcab
输出:
7
|ab|cab 删除“ab” 有三种“cab”,“ab”,“b”
a|bca|b 删除“bca”,有两种“ab”,“a”
ab|cab| 删除“cab”,“ab”
abc|ab| "abc"
输入:
3 1
abc
输出:
5
输入:
5 2
abbab
输出:
12
输入:
48 5
cacabbabcabbabbcabbabcabbabbcabcabbabbacabbabbab
输出
89
题解:
假设前缀和后缀拼接为 newString
我们滑动窗口来解决这个问题,设置两个指针,分别代表两个“|”,对于右指针j的移动,会减少newString的字符个数,移动左指针i会增加newString的个数,因此有情况:
(1)newString不满足情况时,我们需要移动右指针j,删除一些重复个数>k的字符;
(2)当newString满足条件时,我们右指针当前位置即后继位置均满足条件,此时只需要计算后(n-j)的长度,(ps当左指针i在开头字符串最前面时,右指针不能移动到最后)
(3)承接(2),我们可以移动左指针i,如果增加一个字符,依旧满足条件k,则,右指针j,可以相继移动(n-j)为,进行枚举
(3)承接(2),我们可以移动左指针i,如果增加一个字符,不能满足条件k,则,需要返回(1)
1 n, k = list(map(int, input().split())) 2 str1 = input().strip() 3 last = dict() 4 for i in str1: 5 if i not in last: 6 last[i] = 1 7 else: 8 last[i] += 1 9 lk = 0 10 for key,v in last.items(): 11 if v>k: 12 lk += 1 13 14 res = [] 15 i, j = 0, 0 16 count= -1 #删除字串长度len, 1≤len≤n-1, 如果|ab|cab |abc|ab |abca|b 【|abcab|,不成立】 17 while j !=n: 18 for s in range(j, n): 19 last[str1[s]] -= 1 20 if last[str1[s]] == k: 21 lk -= 1 22 if lk == 0: 23 count+=(n-s) 24 break 25 j = s+1 #右指针下一时刻的位置 26 for t in range(i, j): #t∈[i,s] 27 last[str1[t]] += 1 28 if last[str1[t]] > k: 29 lk += 1 30 break 31 if t<s: #删除字串长度len, 1≤len≤n-1, 32 #如果加入的字符,没有破坏>k的协议,那么,已经满足的suffix,可以切开 33 #新加【c】 ab|cb|def abc|b|def abc|bd|ef abc|bde|f abc|bdef| 34 count+=(n-s) 35 i = t+1 36 print(count)