Leetcode刷题记录(12):3无重复字符的最长字串

刷题网站:Leetcode

难度: 中等

语言: Python

计划:从简单——>到中等——>再到难。

一、3无重复字符的最长字串

1.1 问题描述

给定一个字符串s,请你找出其中不含有重复字符串的最长子串的长度。(这里要与最长子序列做区分,最长子串要连续的字符)

  • 示例1
输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3
  • 示例2
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1
  • 示例3
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
  • 示例4
输入: s = ""
输出: 0
1.2 思考分析

最初,我的思考是这样的,既然题目要求不重复的最长子串,那我可以以第一个为起点,与后面的一个一个比,然后以第二个为起点,一个一个与后面比,直到比到重复的记录下,然后往后移动。初步代码如下

for left in range(len(s)):   #假设我只从第一个字符开始为左指针
	right = left + 1   #比左指针加1为右指针开始比
	while s[left] != s[right]:   #只要左指针不等于右指针的值,就右指针往后移
		right += 1
	print(right - left)  #输出最长的子串

从代码上理解我刚开始还觉得行,但是运行后发现会发生溢出(出错),上面的代码仅仅考虑了起始位置固定,与后面字符进行比较,并没有考虑在左指针和右指针内字符的比较,所以是错的。例如,当left = 3时为aright = 4时为b然后,right一直增加到最后都没有与a重复的,看似是满足上面代码abcbb,但是,里面还有b是重复的,所以错了。

所以还需考虑左指针右指针内部的比较,以及右指针溢出的可能,所以代码改如下:

for left in range(len(s)):
right =left +1 
    if left == len(s)-1:
    	break
    else:
    	while s[left] != s[right]:
    		right +=1
    		if s[left+1] == s[right]:
    			break
    	print(right-left)

但是,我们还需要返回不重复子串的最大数呀,所以想到定义一个列表,将right-left的值逐个存入,然后输出最大的数,即

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
    	if s != "":
			list = [1]*len(s)
			for left in range(len(s)):
    			right =left +1 
    			if left == len(s)-1:
    				break
    			else:
    				while right != len(s) and s[left] != s[right]:
    					right +=1
            			if right == len(s) or s[left+1] == s[right]:
            				break
        			list[left] = right-left
			return max(list)
		else:
			return 0

看似把第一个例子带入后,输出的结果也是3,带入第二个例子后也是1,第三个例子输出也是3,带入最后的空,输出也是0,感觉是对的。其实此答案还是错误的,我只是为了凑出结果而编的代码,还是看官方解答吧!!!😂

看了官方解答后的一些思考。

此题提到了无重复字符,则最先考虑用滑动窗口来解答。所以,我们需要知道滑动窗口的含义,举个例子。当考虑字符串为abcabcbb时,我们从左到右,逐个开始为起始位置,来判断最长的子字符串大小(想法与我的类似?)。即

  • 第一个字符为起点时,(a)bcabcbb,则最长走到(abc)abcbb,若再往下“滑动”的话,就会变成(abca)bcbb,有重复a不行。所以最长为3.
  • 第二个字符为起点时,a(b)cabcbb,则最长走到a(bca)bcbb,若再往下“滑动”会有重复,所以最长为3.
  • 第三个字符为起点时,ab(c)abcbb,则最长走到ab(cab)cbb,最长为3.
  • 第四个字符为起点时,abc(a)bcbb,则最长走到abc(abc)bb,最长为3.
  • 第五个字符为起点时,abca(b)cbb,则最长走到abca(bc)bb,最长为2.
  • 第六个字符为起点时,abcab(c)bb,则最长走到abcab(cb)b,最长为2.
  • 第七个字符为起点时,abcabc(b)b,则最长走到abcabc(b)b,最长为1.
  • 第八个字符为起点时,abcabcb(b),则最长走到abcabcb(b),最长为1.

首先注意的点是,起始位置增加后,子串的结束位置也是递增的。我发现,我与原答案的区别在于判断左右指针内的重复字符,官方解释可以用python中的set,即左指针向右移动时,从set中移除一个字符,在右指针向右移动时,往set中添加一个字符。(其中右指针初始值为-1,相当于在左边界,还没开始移动)

修改后的代码如下:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
    	list = set()
    	Max = 0
    	right = -1
    	for left in range(len(s)):
    		if left != 0:
    			list.remove(s[left-1])
    		while right +1  < len(s) and s[right + 1] not in list:
    			list.add(s[right+1])
    			right+=1
    		Max = max(Max, right - left +1)
    	return Max

运行结果显示,击败了39.28%的用户,看来还是不是算好的答案
在这里插入图片描述

1.3 总结

这是第一次解处滑动窗口题目,还是有些地方没注意到,花了挺久时间想的,看官方答案也没完全吸收,后续还要多加练习才行。特别是要注意移动后,增添、删减操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值