題目連結(https://leetcode.com/problems/longest-substring-without-repeating-characters/description/)
Given a string s
, find the length of the longest substring without duplicate characters.
今天來做 medium ,字串比對的題目,並探討不同的資料結構、sliding window演算法的應用
s
s
中不含重複字元的最長子字串0 <= s.length <= 5 * 10^4
邊界條件s
consists of English letters, digits, symbols and spaces.s
的型態可能是英文字母、位元、符號、空格pkew 不行,因為不是子字串,雖然把字串中無重複字母都挑出來,但不滿足 substring 的定義。
Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
i
和 j
分別表示滑動視窗的左右邊界。i
是開始位置,j
是結束位置,隨著 j
的增加,擴展視窗,並檢查是否有重複字符。i
指標來縮小視窗,直到視窗中的字符不再重複。方法一:暴力法
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int res = 0;
for (int i = 0; i < s.size(); i++) {
unordered_set<char> set;
for (int j = i; j < s.size(); j++) {
if (set.find(s[j]) != set.end()) {//發現重複字串
break;
}
set.insert(s[j]); //不重複就加入 set 中
}
res = max(res, (int)set.size()); //更新最長的子字串長度
}
return res;
}
};
方法二:滑動視窗
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char> set;
int i = 0, maxlength = 0;
for (int j = 0; j < s.size(); j++) {
// 移動左邊界,直到當前字符不重複
while (set.find(s[j]) != set.end()) {//發現重複字符
set.erase(s[i]);
i++;
}
set.insert(s[j]); // 加入當前字符到集合
maxlength = max(maxlength, j - i + 1); // 更新最大長度
}
return maxlength;
}
};
方法三:滑動視窗(hash map優化版)
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> mp;
int l = 0, res = 0;
for (int r = 0; r < s.size(); r++) {
if (mp.find(s[r]) != mp.end()) {
l = max(mp[s[r]] + 1, l);
}
mp[s[r]] = r;
res = max(res, r - l + 1);
}
return res;
}
};
假設 s = "pwwkew"
set = {}
, i = 0
, maxLength = 0
j = 0
: set.insert('p')
→ set = {'p'}
→ maxLength = 1
j = 1
: set.insert('w')
→ set = {'p', 'w'}
→ maxLength = 2
j = 2
: set.find('w') != set.end()
→ i = 1
, set.erase('p')
→ set = {'w'}
j = 2
: set.insert('w')
→ maxLength = 2
j = 3
: set.insert('k')
→ set = {'w', 'k'}
→ maxLength = 3
j = 4
: set.erase('w')
→ i = 2
, set = {'k'}
j = 4
: set.insert('k')
→ maxLength = 3
maxLength = 3
i
和 j
管理一個區間 [i, j]
,這個區間內不包含重複字符。set.end()
:這是一個特殊的迭代器,它指向集合的結尾,表示在集合中找不到該元素。set.find(s[j]) != set.end()
:這裡我們是在檢查 s[j]
是否存在於 set
中。
find()
會返回一個有效的迭代器,這個迭代器不是 set.end()
,所以條件為 true
,進入 while
迴圈s[j]
不在 set
中,find()
會返回 set.end()
,條件為 false
,跳過 while
迴圈。ps. 部分內容經 AI 協助整理