LeetCode系列:3 Longest Substring Without Repeating Characters
阿新 • • 發佈:2018-12-09
Q:Given a string, find the length of the longest substring without repeating characters.
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.
E:給定一個字串,計算出不重複的最長子串的長度。
e.g.
Example 1:
輸入: "abcabcbb"
輸出: 3
解釋: 最長不重複子串是"acb"且長度為3
Example 2:
輸入: "bbbbb"
輸出: 1
解釋: 最長不重複子串是"b"且長度為1
Example 3:
輸入: "pwwkew"
輸出: 3
解釋: 最長不重複子串是"wke"且長度為3,請注意答案必須是子串,"pwke"是子序列而不是子串
A:
因為只需要計算最長長度,不需要記錄子串,所以我們可以利用Dictionary或者Set不能重複的特性來儲存當前遍歷過的串,遇到相同字元,也就是key存在重複。
Approach 1:
方法一先考慮使用Dictionary的實現方式。這裡key是遍歷的字元,value是該字元在該字串中的序號(不是下標)。我們使用一個變數記錄當前子串的開始下標,當遇到重複字元的時候,這時我們需要去比較當前子串和上一個子串(若沒有則為0)的長度,更新當前子串的開始下標(重複字元的下標加一或者還是當前開始下標),更新重複字元的下標,直到字串遍歷結束。
class Solution {
func lengthOfLongestSubstring(_ s: String) -> Int {
var begin = 0 //當前子串的開始下標
var maxLength = 0 //當前獲取的子串的最長長度
var map : [Character : Int] = [:] //key為字元,value為字元的序號(下標+1)
for (index, value) in s.enumerated() {//普通for迴圈與enumerated()效能差別很大,所以儘量使用enumerated(),在這個演算法中,使用不同的for迴圈,效能相差達到100倍
if let existingIndex = map[value] { //存在重複字元
begin = max(existingIndex, begin) //更新當前子串的開始下標
}
maxLength = max(maxLength, index-begin+1)//更新當前獲取到的子串的最大長度
map[value] = index+1 //更新重複字元的下標
// print(map)
}
return maxLength
}
}
Complexity Analysis:
- 時間複雜度: O(n)。(LeetCode:64 ms)
- 空間複雜度:O(n)。
Approach 2:
方法二先考慮使用Set的實現方式。思路和方法一差不多,沒有遇到相同字元的時候,將字元加入到Set中;遇到相同的字元時,更新最長子字串的長度,更新當前子串的開始下標,同時判定當前字串是不是重複的字元,若不是,將字元從Set中移除,當前子字串的開始下標+1直到遇到相同字元。(如字串是:“abcdecf"子字元是"abcde”,這時遇到相同字元’c’,需要將"ab"從Set中移除,begin指到第一個’c’的位置)。與方法一不同的是,如果最長的子字元是最後那個子串,這樣是遍歷不出的,所以還需要做一次比較:max(maxLength, charArray.count-begin)。
class Solution {
func lengthOfLongestSubstring(_ s: String) -> Int {
var maxLength = 0
var begin = 0
var set = Set<Character>()
let charArray = Array(s)
for (index, char) in charArray.enumerated() {
if set.contains(char) {
maxLength = max(maxLength, index-begin)
while charArray[begin] != char {
set.remove(charArray[begin])
begin += 1
//print(set)
}
begin += 1
//print(set)
} else {
set.insert(char)
//print(set)
}
}
return max(maxLength, charArray.count-begin)
}
}
Complexity Analysis:
- 時間複雜度: O(n)。(LeetCode:76 ms)
- 空間複雜度:O(n)。
Approach 3:
class Solution {
func lengthOfLongestSubstring(_ s: String) -> Int {
var hash = [Int](repeating: 0, count: 256)
let str = Array(s.utf8).map { Int($0) }
let len = str.count
var ans = 0
var j = 0
for i in 0..<len {
while j < len && hash[str[j]] == 0 {
hash[str[j]] = 1
j += 1
print(hash)
}
ans = max(ans, j - i)
hash[str[i]] = 0
print(hash)
}
return ans
}
}
Complexity Analysis:
- 時間複雜度: O(n)。(LeetCode:36 ms)
- 空間複雜度:O(n)。