题目描述
解法一:动态规划+哈希表查找
Java
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.isEmpty()) return 0; // 等同于判断 s.length()是否等于0
HashMap<Character, Integer> map = new HashMap<>(); // 创建一个hashmap用于记录各字符最后一次出现的索引位置
int curLength =0, maxLength = 0; // curLength 记录当前不含重复字符的子串长度,maxLength 记录全局的最长不重复子串的长度
for(int i=0; i<s.length(); i++){
int preIndex = map.getOrDefault(s.charAt(i),-1); // 获取最近的上一个与当前字符相同的字符所在索引位置
if(preIndex < 0 || i > preIndex + curLength) // 若之前还没有遇到相同字符,或者上一个重复字符出现在当前不重复子串之外,则子串长度+1
curLength++;
else // 否则说明上一个重复字符出现在当前不重复子串之中,则子串左边界更新为上一个重复字符的下一个位置,即保留 [preIndex+1, i]范围内的字符。
curLength = i - preIndex;
map.put(s.charAt(i), i); // 更新哈希表
maxLength = Math.max(maxLength, curLength); // 更新全局最长不重复子串的长度
}
return maxLength;
}
}
Python
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
dic = {}
curLength, maxLength = 0, 0
for i in range(len(s)):
preIndex = dic.get(s[i], -1)
if preIndex < 0 or i - preIndex > curLength:
curLength +=1
else:
curLength = i - preIndex
dic[s[i]] = i
maxLength = max(maxLength, curLength)
return maxLength
解法二:动态规划+线性查找
Java
左边界 i 获取方式: 遍历到 s[j] 时,初始化索引 i = j - 1,向左遍历搜索第一个满足 s[i] = s[j] 的字符即可 。
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> dic = new HashMap<>();
int res = 0, tmp = 0;
for(int j = 0; j < s.length(); j++) {
int i = j - 1; // 当遍历到字符 s[j]时,初始化索引 i=j-1,向左遍历搜索第一个满足 s[i]=s[j]的字符
while(i >= 0 && s.charAt(i) != s.charAt(j)) i--; // 线性查找 i
tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j]
res = Math.max(res, tmp); // max(dp[j - 1], dp[j])
}
return res;
}
}
Python
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
dic = {}
res, tmp = 0, 0
for i in range(len(s)):
left = i - 1
while left >= 0 and s[left] != s[i]:
left -= 1
if i - left > tmp:
tmp += 1
else:
tmp = i - left
res = max(res, tmp)
return res
解法三:双指针 + 哈希表
Java
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> dic = new HashMap<>(); // 哈希表用于记录每个字符最后一次出现的位置
int i = -1, res = 0; // 左指针 i始终指向不重复字符子串的左边界
for(int j = 0; j < s.length(); j++) {
if(dic.containsKey(s.charAt(j))) // 判断当前遇到的字符是否之前出现过
i = Math.max(i, dic.get(s.charAt(j))); // 如果发现重复了,更新左指针 i为上一个重复字符的位置,保证区间[i+1,j]内无重复字符且长度最大
dic.put(s.charAt(j), j); // 更新哈希表中字符 s[j]最后出现的位置
res = Math.max(res, j - i); // 比较上轮 res和本轮双指针区间 [i+1,j]的宽度(即 j - i),更新最大长度
}
return res;
}
}
Python
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
dic = {}
left = -1
res = 0
for i in range(len(s)):
if s[i] in dic:
left = max(left, dic.get(s[i])) # 更新左指针
dic[s[i]] = i
res = max(res, i-left)
return res
复杂度分析:
- 时间复杂度:O(N),for循环遍历字符串中的每个字符,需要 O(N) 的时间
- 空间复杂度:O(1),字符的 ASCII 码范围为 0 ~ 127 ,哈希表 dic 最多使用 O(128) 即 O(1) 大小的额外空间。