问题:给定一个字符串,查找不重复的最长子字符串的长度。
Example 1:
Input: "abcabcbb"
Output: 3
Explanation: The answer is "abc"
, with the length of 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: The answer is "b"
, with the length of 1.
Example 3:
Input: "pwwkew" Output: 3 Explanation: 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.
方法1:两重循环,暴力查找
我用木鱼脑袋想出来的方法其实就是我们的通常的思维逻辑。从第一个字符开始往后查看,边查看边计数,下一个字符只要和之前所遇到的连续的字符都不一样,则不重复字符串长度加1。如果遇到和之前连续字符串中相同的字符,则本次查找结束,从第二个字符开始重复这个过程。最后返回所有查找次数中长度最长的那个长度。时间复杂度为O(n²),测试显示超时o(╥﹏╥)o。
#Python
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
if len(s) == 1:return 1 #对长度为1的字符串单独处理
d = {};l = n = 0 #字典d用来存储每次查找中已经找过的字符
for i in range(len(s)): #依次以每个字母为开头进行查找
for j in range(i,len(s)):
if s[j] not in d: #本次查找中字符没出现过
d[s[j]] = j;n = n + 1 #n记录本次查找中的不同字符数串长度
if n > l:l = n #l记录所有查找次数中的最长字符串长度
else:
d = {};n = 0 #如果出现重复字符,则本次查找结束,d和n清空以备下次查找
break
return l
方法2:滑动窗口
这是一个简单的想法,假设有字符串”abcabcad”,显然最长不重复字段长度为3,如果我们能找到第0个字符a和第3个字符a,直接用它们的下标相减,就能得到所要长度。所以关键就是找到一个字符串的首位下标和第一个重复元素的下标。以Python代码为例,l = max(l,j-i+1),假如字符串全都不同,那么末尾减去首位加上1才是全长,所以是j-i+1,不是j-i;d[s[j]] = j + 1是跟j-i+1对应的,设有一段字符串”bcdancd”,最长非重复段在”dancd”里,长度为4,如果d[s[j]] = j ,那么第一个d对应的下标是i=2,第一个重复的d对应的下标是j=6,那么l = max(l,j-i+1)计算出来为5,即把重复的那个字符也算进长度里了。该算法时间复杂度为O(n)。
#Python
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
d = {};l = 0;i = 0
for j in range(len(s)):
if s[j] in d: #遇到重复字符
i = max(i,d[s[j]]) #求最近的重复字符
l = max(l,j-i+1) #求最大长度
d[s[j]] = j + 1 #d用来存放相同字符最近的下标值
return l
//C++
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n = s.length(),l = 0;
std::unordered_map<int,int> m;
for(int j = 0,i = 0;j < n;j++){
if (m.find(s[j]) != m.end()){
i = max(i,m[s[j]]);
}
l = max(l,j - i + 1);
m[s[j]] = j + 1;
}
return l;
}
};