文章目錄
1. 題目
請從字符串中找出一個最長的不包含重複字符的子字符串,計算該最長子字符串的長度。
例子:
“abcabcbb” “abc” 長度爲3
“bbbbb” “b” 長度爲1
“dvdf” “vdf” 長度爲3
2. 解題思路
詳情見 面試題48. 最長不含重複字符的子字符串(動態規劃 / 雙指針 + 哈希表,清晰圖解)
2.1 暴力法
記錄子串的起點和終點,分別爲 i 和 j,當子字符串重複之後,從 i + 1重新計算最長不重複子字符串。
2.2 滑動窗口
0). 初始化頭尾指針 head,tail;
1). tail 指針右移,判斷 tail 指向的元素是否在 [head:tail] 的窗口內;
2). 如果窗口中沒有該元素,則將該元素加入窗口,同時更新窗口長度最大值,tail 指針繼續右移;
3). 如果窗口中存在該元素,則將 head 指針右移,直到窗口中不包含該元素。
4). 返回窗口長度的最大值。
2.3 優化的滑動窗口(雙指針+hash表)
與上面的不同之處在於,使用hash表記錄了字符的下標,當該字符重複時,直接去到該下標+1的位置,避免了重複比較。
2. 動態規劃
3. 代碼實現
3.1 暴力法
O(n2) + S(n)
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
"""
1. 暴力法
"""
max_count = 0 # 最長不重複子字符串的長度
record = set() # 記錄當前子串中以有哪些字符
i, j = 0, 0 # 記錄子串的起點和終點
while i <= j and j < len(s):
if s[j] not in record: # 如果子串沒重複,長度+1
record.add(s[j])
j += 1
else: # 如果子串重複了,重置record
i = j = i+1
record.clear() # 清空
if len(record) > max_count: max_count = len(record)
return max_count
3.2 滑動窗口
O(n2) + S(n)
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
head = 0
tail = 0
if len(s) < 2: return len(s) # 邊界條件
res = 1
while tail < len(s) - 1:
tail += 1
if s[tail] not in s[head: tail]:
res = max(tail - head + 1, res)
else:
while s[tail] in s[head: tail]:
head += 1
return res
作者:z1m
鏈接:https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/solution/tu-jie-hua-dong-chuang-kou-shuang-zhi-zhen-shi-xia/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
3.3 滑動窗口+hash表
O(n) + S(n)
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
n = len(s)
hashmap = {}
head, res = 0, 0
for tail in range(n):
if s[tail] in hashmap:
head = max(hashmap[s[tail]], head)
hashmap[s[tail]] = tail + 1
res = max(res, tail - head + 1)
return res
作者:z1m
鏈接:https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/solution/tu-jie-hua-dong-chuang-kou-shuang-zhi-zhen-shi-xia/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
3.4 動態規劃
O(n) + S(1)
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
dic = {}
res = tmp = 0
for j in range(len(s)):
i = dic.get(s[j], -1) # 獲取索引 i
dic[s[j]] = j # 更新哈希表
tmp = tmp + 1 if tmp < j - i else j - i # dp[j - 1] -> dp[j]
res = max(res, tmp) # max(dp[j - 1], dp[j])
return res
作者:jyd
鏈接:https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/solution/mian-shi-ti-48-zui-chang-bu-han-zhong-fu-zi-fu-d-9/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
4. 總結
降低時間複雜度的關鍵在於,如何避免重複比較。
5. 參考文獻
[1] 劍指offer叢書
[2] 劍指Offer——名企面試官精講典型編程題