【LeetCode】【3】Longest Substring Without Repeating Characters

本文最后更新于:2021年12月22日 中午

【主页】系列文章目录

【LeetCode】系列目录


LeetCode系列

Q:Given a string, find the length of the longest substring without repeating characters.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)的长度,更新当前子串的开始下标(重复字符的下标加一或者还是当前开始下标),更新重复字符的下标,直到字符串遍历结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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)。

联系方式

邮箱: xiebangyao_1994@163.com

相关账号: