题目

LeetCode 刷题记录 |003:无重复字符的最长子串_java

审题

今天这道题,看起来是不是很简单?

但做为一道中等难度的题目,它可不会让你失望。敲起你的键盘,试着来解下这道题,你会很难找到一个好的思路。

事实上,想这个思路也确实花了我不少的时间,是写代码时间的好几倍。

首先,要理解 子串 和 子序列 的区别。

子串:必须同时具备,连续性和唯一性。
子序列:只须具备唯一性即可。

我的版本

先说下我的思路。

假设一个字符串的长度是10,那我就先从字符串的[0,1]子串查起,假如子串里没有重复字符(通过set()去重查看),就继续查看子串[0,2],如果还是没有重复,就继续查看[0,3],这时候,我们发现这个子串里有重复字符(比方说,子串"abcb"),接下来,我们就要找出是在重复的那个字符的索引(查出是 b,在索引 处)。那下次我们查找的子串就不是[0,5]了,而是[2,5],就这样一直往下,直到遍历完整个字符串。

class Solution:
   def lengthOfLongestSubstring(self, s):
       if len(s) == 1:
           return 1

       reset_start= False
       start = 0
       max_len = 0

       for i in range(len(s)):
           # reset_start就为True,需要重新设置起点
           if reset_start:
               start = new_start

           # 为什么加1,是因为第一次start会和end一样是0
           end = i + 1
           sub_str = s[start:end]
           len_sub_str= end - start

           if len(set(sub_str)) != len_sub_str:
               # 找出是在哪个位置重复
               rep_index = sub_str.index(s[i])
               new_start = rep_index + start + 1
               reset_start= True
               continue

           if len_sub_str > max_len:
               # 记录下迄今为止最在长度
               max_len = len_sub_str
           skip = False

       return max_len

运行一下,结果很差。只击败了24.73%。今天吃不了鸡腿了。不过小明真的是尽力了。只能想到这个思路。

LeetCode 刷题记录 |003:无重复字符的最长子串_java_02

网上的版本

按照惯例,还得上网去学习别人的优秀代码。

真是惊叹,果然是思路决定出路啊。

这种解法很巧妙。

定义两个变量longestleftlongest用于存储最长子字符串的长度,left存储无重复子串左边的起始位置。

然后创建一个哈希表,遍历整个字符串,如果字符串没有在哈希表中出现,说明没有遇到过该字符,则此时计算最长无重复子串,当哈希表中的值小于left,说明left位置更新了,需要重新计算最长无重复子串。每次在哈希表中将当前字符串对应的赋值加1。

class Solution(object):
   def lengthOfLongestSubstring(self, s):
       longest = 0; left = 0; tmp = {}

       for index, each in enumerate(s):
           if each not in tmp or tmp[each] < left:
               # 计算当前最长的长度
               longest = max(longest, index - left + 1)
           else:
               left = tmp[each]
           tmp[each] = index + 1

       return longest

运行一下,看看吧,击败了92.3%。众望所归啊。 佩服佩服。

LeetCode 刷题记录 |003:无重复字符的最长子串_java_03

总结

其实我的思路,和上面那个优秀代码的思路是一致的。

我做得不好的一点是,在检测当前子串是否重复这一点上面,我选了一个效率非常低的做法,就是每次循环都要计算下len(set(str_obj)) 和 len(str_obj),而这种是相当耗时的,而且会随着字符串长度的增长,耗时也线性增加。

而聪明的人,则是通过维护一个字典,来存放唯一值,和唯一值的最大索引。对执行速度的提升,可以说是非常显著的。