Python每日一练-----无重复字符的最长子串

(day26)

题目:

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成

示例 1:

输入: s = "abcabcbb"

输出: 3

说明: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"

输出: 1

说明: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
说明: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

题目分析:

看过例题我们可以知道题意要求我们寻找字符串s中连续且不重复的子字符串。需要注意这个字符串可以是空格,或者为空。

解题思路:

那么如何寻找这个连续且不重复的子字符串?

这里提供一个思路是放置指针若出现重复的字符则移动指针,计算更新最大子字符串来确定这个连续不重复子字符串的长度。

怎么理解呢?

以例3为例 s = "pwwkew"

我们先在字符第一个字符放置指针 i 和 j

Python每日一练-----无重复字符的最长子串_第1张图片

 接着将遍历字符串s,遍历的同时移动指针j,因为不重复的要求,所以我们将字符串s的字符s[j]以键值对的方式加入到字典dic中,其中键是s[j],值为指针j(也就是s[j]所在位置),这样我们就记录了已经出现过的字符。

如果后面不会遇见重复的字符(也就是遍历到的字符不在字典dic中)

那么最长的连续子字符串的长度就 = j - i

如果后面会遇到重复的字符(也就是遍历到的字符在字典dic中)

那么我们就需要先保存当前的最长子字符串,然后再移动指针i去找到下一个最长子字符串

我们可以将这些”最长“子字符串添加到一个列表,然后使用max()函数找到最长子字符串即可。但是为了减少空间复杂度,提高运行速度,我们不使用列表。假设我们找到当前第一个最长子字符串s1,再移动指针后找到最长子字符串s2,接着又找到第3个最长子字符串s3,我们再找到第二个最长子字符串s2时,就将其与s1比较并取s1,s2最大值。如果最大值为s1,再将其与s3比较并取最大值,这样仅使用一个变量就可以不断更新储存最长子字符串。

那么指针i的移动方式是什么?

上面已经说明当后面不在遇到重复的字符时不需要移动指针i,(这里的”后面“可以理解为字符串s后续的一个片段)

所以我们现在讨论后面出现重复字符的情况。

因为后面出现重复字符那么i指针移动规则应该为 i = max(dic[s[j]], i)

dic[s[j]]表示该字符第一次出现所在字符串的位置

为什么i 指针的移动方式不是 i = dic[s[j]]?

我们的思路是找出两重复字符间的距离来求最长字符串,但是不能直接将i指针放置为dic[s[j]。

-----------------------------------

比如这种情况 s = ‘abba’。

dic = {‘a’:0,‘b’:1}

如果i = dic[s[j],那么当j遍历到第二个a时,i对应的值为0,j = 3,j - i = 3,答案错误。

所以我们需要使用 i = max(dic[s[j]], i),注意到两个a中间又两个b,那么j遍历到第二个b时b已出现再字典中i指针移动,因为 i = max(dic[s[j]], i)此时的i就为1,所以当j遍历到最后的a时就有j-i=2答案正确。

--------------------------------------------------------------

代码实现

def lengthOfLongestSubstring(s):
    dic = {}
    i, ans = -1, 0

    for j in range(len(s)):
        if s[j] in dic:
            i = max(dic[s[j]], i)

        ans = max(ans, j - i)
        dic[s[j]] = j

    return ans

代码注释

def lengthOfLongestSubstring(self, s):
    dic = {}  # 字典,key是字符串中的字符,value是字符所在位置
    i, ans = -1, 0  # i用来做start指针,ans用来记录最大长度
    
    for j in range(len(s)):  # j用来做end指针,遍历字符串中的每一个字符
        if s[j] in dic:  # 若s[j]在字典中,即出现重复字符,需要移动初始指针i
            i = max(dic[s[j]], i)  # 初始指针向右移动,取指针i和对应第一次出现字符位置最大值
            
        ans = max(ans, j - i)  # 更新最大长度,上次的长度,与更新后的长度取最大
        dic[s[j]] = j  # 更新j指针所指字符对应的值
        
    return ans

这里为什么要初始化指针i为-1?

这是因为指针j开始时为0,如果指针i也初始化为零,那么当s = ‘a’只有单个字符时,j - i=0,解答出错。初始化i = -1就是针对s只有单个字符的情况。

今天就到这,明天见。

❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄end❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄

你可能感兴趣的:(力扣每日一卷,python,算法,学习,窗口移动,力扣刷题)