【leetcode】3. 无重复字符的最长子串(经典!!!)

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。(采用hashmap和two sum一样)

示例 :

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

双指针:

动态规划:

  • 状态表示 本题 dp[i]dp[i] 表示以第 ii 个元素结尾的不含重复字符的最大子串长度;
  • 状态转移方程 如果第 ii 个元素,在前 i-1i-1 个元素中未出现,我们可以直接将第 ii 个元素加入到上一个最大子串中,此时 dp[i] = dp[i-1]+1;如果第 ii 个元素,在前 i-1i-1 个元素中已出现,那么我们需要计算,在前 i-1i-1 个元素中,最近一次出现第 ii 个元素的位置,并计算出二者的间距distancedistance。如果 distance>dp[i-1]distance>dp[i-1],说明重复的元素不影响当前不含重复字符的最大子串长度,所以 dp[i] = dp[i-1]+1,如果distance≤dp[i-1]distance≤dp[i-1],说明以第 ii 位 元素结尾的,最大无重复字符的子串,是从上一个重复元素的下一位开始,到当前第 ii 位元素结束,此时dp[i] = distance
  • 边界条件 当 i=0i=0 时,dp[0] = 1

在本题中,需要记录第 ii 个元素有无出现过,如果出现过,它最近一次出现的位置在哪,所以我们可以创建一个字典结构,来保存上述信息。

class Solution:
    def longestSubstringWithoutDuplication(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        dp = [0] * len(s) #dp[i]表示以第i个元素结尾的不含重复字符的最大子串长度
        d = dict() # 用来记录26个字母,上一次出现的位置
        res = 0
        for i in range(0,len(s)):
            if s[i] not in d.keys(): # 第i个元素在之前未出现
                dp[i] = dp[i-1]+1
            else:
                distance = i - d[s[i]]
                if distance > dp[i-1]:
                    dp[i] = dp[i-1]+1
                else:
                    dp[i] = distance 
            d[s[i]] = i # 更新第i个元素最后出现的位置
            res = max(res,dp[i])
        return res

分析:

我们只关心每个字符最后出现的位置,并建立映射。

窗口的右边界就是当前遍历到的字符的位置,为了求出窗口的大小,我们需要一个变量left来指向滑动窗口的左边界,

(1)如果当前遍历到的字符从未出现过,那么直接扩大右边界,

(2)如果之前出现过,那么就分两种情况,在或不在滑动窗口内,如果不在滑动窗口内,那么就没事,当前字符可以加进来,如果在的话,就需要先在滑动窗口内去掉这个已经出现过的字符了。(去掉的方法并不需要将左边界left一位一位向右遍历查找,由于我们的HashMap已经保存了该重复字符最后出现的位置,所以直接移动left指针就可以了。我们维护一个结果res,每次用出现过的窗口大小来更新结果res,就可以得到最终结果了)

需要定义两个变量res和left,其中res用来记录最长无重复子串的长度,left指向该无重复子串左边的起始位置,然后我们遍历整个字符串,对于每一个遍历到的字符,如果哈希表中该字符串对应的值为0,说明没有遇到过该字符,则此时计算最长无重复子串,i - left +1,其中now是当前最长无重复子串最右边的位置,left是最左边的位置,还有一种情况也需要计算最长无重复子串,就是当哈希表中的值小于left,这是由于此时出现过重复的字符,left的位置更新了,如果又遇到了新的字符,就要重新计算最长无重复子串。最后每次都要在哈希表中将当前字符对应的值赋值为i+1。

 res = max(res, i - left + 1) # 省去了繁琐的if条件判断

代码:

class Solution(object):
    def lengthOfLongestSubstring(self, s):

        hash_map = {}
        left,res = 0,0
        for i in range(len(s)): # i就是now,
            # 如果当前字符从没出现过,或者是出现了,但不包含在当前窗口内:
            if s[i] not in hash_map or left>hash_map[s[i]]:
               res = max(res,i-left+1)
            else:
                left = hash_map[s[i]]+1

            hash_map[s[i]] = i
        print(hash_map)
        return res

参考:

https://www.cnblogs.com/ariel-dreamland/p/8668286.html 

你可能感兴趣的:(leetcode,leetcode解题记录)