3. Longest Substring Without Repeating Characters

题目描述

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

示例:

给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是3。

给定 "bbbbb" ,最长的子串就是 "b" ,长度是1。

给定 "pwwkew" ,最长子串是 "wke" ,长度是3。请注意答案必须是一个子串"pwke"子序列 而不是子串。

我的解法——DP(AC)

  • 一个子串不可能出现重复的字符,那么我们可以用两个指针,一个指针用来遍历字符串,两个指针之间保持无重复字符,那么两个指针之间的长度即最大子串的长度。当发现有重复的字符时,另一个指针指向这个字符上一次出现的位置的下一个字符,继续遍历,直到找到最长子串。
  • 时间复杂度O(n2),空间复杂度O(n)
  • Beat 75%
class Solution:
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        length = len(nums)
        l = 0
        r = length - 1
        
        while(l <= r):
            print(str(l) + ' ' + str(r),)
            mid = int((r - l)/2 + l)
            if(nums[mid] <= nums[r]): # 右面sorted
                if(target == nums[mid]):
                    return mid
                elif(target > nums[mid] and target <= nums[r]):
                    l = mid + 1
                else:
                    r = mid - 1
            else: # 左面sorted
                if(target == nums[mid]):
                    return mid
                elif(target < nums[mid] and target >= nums[l]):
                    r = mid - 1
                else:
                    l = mid + 1
        return -1

最优解法——DP+hashset

  • 加一个hashset,就能保证时间复杂度O(n)
    • 使用 HashSet 将字符存储在当前窗口 [i, j)(最初 j = i)中。 然后我们向右侧滑动索引 j,如果它不在 HashSet 中,我们会继续滑动 j。直到 s[j] 已经存在于 HashSet 中。此时,我们找到的没有重复字符的最长子字符串将会以索引i开头。如果我们对所有的i这样做,就可以得到答案。 =>这里是不断固定左边,滑动右边,和我的方法差不多。
    • 上述的方法最多需要执行 2n 个步骤。事实上,它可以被进一步优化为仅需要 n 个步骤。我们可以定义字符到索引的映射,而不是使用集合来判断一个字符是否存在。 当我们找到重复的字符时,我们可以立即跳过该窗口。 也就是说,如果 s[j]在 [i, j) 范围内有与 j’重复的字符,我们不需要逐渐增加i 。 我们可以直接跳过 [i,j′] 范围内的所有元素,并将i变为 j’ + 1。
  • 时间复杂度O(n),空间复杂度O(n)。

参考答案

  • https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/