LeetCode3. Longest Substring Without Repeating Characters

题目:

Given a string, find the length of the longest substring without repeating characters.

Examples:

Given "abcabcbb", the answer is "abc", which the length is 3.

Given "bbbbb", the answer is "b", with the length of 1.

Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring, "pwke" is a subsequence and not a substring.

原始思路:

首先想到遍历的方法,从左往右遍历字符串,给出每个位置对应的最长子字符串长度。为了不用每次都重新遍历,需要一个辅助字符串来帮助判定。代码如下:

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        max_len = 0
        tmp = ''
        for char in s:
            if char not in tmp:
                tmp += char
                max_len = max(max_len, len(tmp))
            else:
                tmp = tmp[tmp.find(char) + 1:] + char
        return max_len

假设字符串长度为n, char从左到右迭代了n次。每次迭代需要判断char是否在tmp中。鉴于字符串的存放并没有使用hash方法,这一查找的时间复杂度为O(k),k为最长不含重复字符的子字符串长度。故总的时间复杂度为O(kn),空间复杂度为O(k)。这样的时间复杂度还是有些高。

优化:

既然字符串的in查找时间复杂度比较高,想到可以快速查找的集合和字典数据结构。因为这两种数据结构是无序的,因此需要定义一个左指针和右指针,去描述子字符串的位置。

若使用集合,当遍历的char不在集合中时,添加元素很方便;当遍历的char在集合中时,则需要更新左指针的位置,并删除集合中的元素。具体删除方法是不断右移左指针,并删除左指针在集合中对应的元素。知道左指针指向的元素和右指针指向的元素相同。时间复杂度为O(n)

这种方式需要删除集合中元素,仍比较麻烦。参考leetcode讨论区@cbmbbz的解答,发现可以用词典存储字符及其对应的位置,由此更新左指针只需将左指针和重复字符出现的位置进行比较即可,也无需删除字典中元素。时间复杂度也是O(n)(具体应该比上一种方法快一些)。代码如下:

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        left, max_len = 0, 0
        index_dict = {}
        for right, char in enumerate(s):
            if char in index_dict:
                left = max(left, index_dict[char] + 1)
            index_dict[char] = right
            max_len = max(max_len, right - left + 1)
        return max_len
posted @ 2018-06-05 11:09  板弓子  阅读(119)  评论(0编辑  收藏  举报