滑动窗口算法求最大无重复子串长度:
**
1.维护一个起始长度为0的窗口,窗口内都是没有重复的字符。
2.逐个遍历接收到的字符串,如果新遍历到的字符没有在窗口中出现过,那么窗口就“吃掉”这个字符,窗口右边界索引+1,左边界保持不变。
3.如果连续遍历到的字符都没有出现在窗口中,那么窗口将连续扩大。
4.如果遍历的字符在窗口中出现过,那么左窗口向右移动。
5.持续进行遍历,直到最后一个字符。
6.窗口只会扩大,不会缩小,每次记录窗口的最大值。
**
话不多说,来人,上代码!
方法一:逻辑难懂,复杂度高
def lengthoflongestsubstring(s):
dic,maxln,start_index={},0,0
all_str=[]
for index,item in enumerate(s):
if item in dic: #如果窗口中存在当前字符,则左边界向右移动
start_index=max(start_index,dic[item]+1)
maxln=max(maxln,index-start_index+1) #如果不存在,则扩大窗口
windows=s[index +1- maxln:index+1] #得到窗口中的子串
all_str.append(windows) #记录所有子串到列表
dic[item] = index
#print("所有子窗口为%s" %all_str)
unexpect_str=[]
for obj in all_str:
for i in range(len(obj)):
if obj.count(obj[i])!=1 or len(obj)<maxln:
unexpect_str.append(obj)
for j in unexpect_str:
if j in all_str:
all_str.remove(j)
final_result=set(all_str)
print("最长无重复字符串为:%s" %final_result)
print("最长无重复子串长度为:%s" %(maxln))
str=input('请输入字符串:').replace(' ','') #去掉空格,空格会对结果有影响
lengthoflongestsubstring(str)
举例:输入字符串abcadaa:
运行结果:
请输入字符串:abcadaa
最长无重复字符串为:{'bcad'}
最长无重复子串长度为:4
整个过程:
举例:输入字符串:abcadaa
首先定义一个空字典:dic={},最大无重复子串长度maxln=0,字符起始位置start_index=0
使用enumerate函数,产生字符串“abcadaa”每个字符对应的index
每次循环都执行:dic[item] = index,更新字典key或给字典加入新的key
第一轮循环:item=a,a的index=0。因为dic为一个空字典,所以'a'不在dic里面,直接跳过if执行:maxln=max(maxln,index-start_index+1)语句
那么:maxln=max(0,0-0+1)=1,窗口长度为1
第一轮循环结束的结果:maxln=1,start_index=0,dic={a:0}
第二轮循环:item=b,b的index=1,同样b不在dic里面:
那么:maxln=max(1,1-0+1)=2,窗口长度为2
第二轮循环结束的结果:maxln=1,start_index=0,dic={a:0,b:1}
第三轮循环:item=c,c的index=2,同样c不在dic里面:
那么:maxln=max(2,2-0+1)=3,窗口长度为3
第三轮循环结束的结果:maxln=3,start_index=0,dic={a:0,b:1,c:2}
第四轮循环:item=a,a的index=3,a在dic里面,进入if语句执行:start_index=max(start_index,dic[item]+1)
那么:start_index=max(0,0+1)=1 这里的dic[item]为dic里面的值0,并不是当前a的index。窗口左边索引向右移动,从0位置到1位置
maxln=max(3,3-1+1)=3,窗口长度不增加仍为3
第四轮循环结束的结果:maxln=3,start_index=1,dic={a:3,b:1,c:2},a的key值更新了。
第五轮循环:item=d,d的index=4,同样d不在dic里面:
那么:maxln=max(3,4-1+1)=4,窗口扩大为4
第五轮循环结束的结果:maxln=4,start_index=1,dic={a:3,b:1,c:2,d:4}
第六轮循环:item=a,a的index=5,a在dic里面:进入if语句执行:start_index=max(start_index,dic[item]+1)
那么:start_index=max(1,3+1)=4
maxln=max(4,5-4+1)=4,窗口长度不变
第六轮循环结束的结果:maxln=4,start_index=4,dic={a:5,b:1,c:2,d:4}
第七轮循环:item=a,a的index=6,a在dic里面:进入if语句执行:start_index=max(start_index,dic[item]+1)
那么:start_index=max(4,5+1)=6
maxln=max(4,6-6+1)=4,窗口长度不变
第七轮循环结束的结果:maxln=4,start_index=6,dic={a:6,b:1,c:2,d:4}
循环结束,最终结果:
maxln=4,start_index=6,dic={'a':6,'b':1,'c':2,'d':4}
至于求最长无重复子串:
在所有的窗口子串组成的列表中,删除掉有重复字符和长度小于最大无重复子串长度的子串,就可以得到了。
方法二:复杂度低,逻辑易懂
附上力扣原题链接:
https://leetcode.cn/problems/longest-substring-without-repeating-characters/
题目只要求最长无重复子串长度,这里将最长无重复子串一并输出
逻辑:
定义初始为空的字符串,遍历题目给定字符串,如果该字符在初始字符串中出现过,那么将初始字符串切片为该字母第一次出现位置后面的片段,并维护一个最长的长度;如果该字符未在初始字符串中出现,那么直接初始字符串直接追加该字符。维护最长的初始字符串,就得到了最长子串和最长子串长度
代码:
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s:
return 0
else:
zichuan = ""
max_len = 0
for i in s:
if i in zichuan:
if len(zichuan) > max_len:
max_len =len(zichuan) #得到最长子串长度
max_zichuan = zichuan #得到最长子串
index = zichuan.index(i)
zichuan = zichuan[index+1:]
zichuan += i
else:
zichuan += i
return max(max_len,len(zichuan)),max_zichuan
a = Solution()
print(a.lengthOfLongestSubstring("pwwkew"))
输出最长子串长度以及最长无重复子串:
E:\pycharm_project\venv\Scripts\python.exe E:/pycharm_project/venv/2.py
(3, 'wke')
力扣通过率: