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.
给一个字符串,输出最长子串的长度,要求子串中不含重复字母。
最简单的就是暴力枚举子串的首尾( O ( n 2 ) O(n^2) O(n2)),然后判断每个子串是否符合要求( O ( n ) O(n) O(n)),总的复杂度是 O ( n 3 ) O(n^3) O(n3)
进一步,可以用一个 map
来存每个字母上一次的出现位置,当枚举的尾指针右移时,更新一下新字母的次数,假如该字母已经出现过,并且该位置在当前头尾指针的区间内,则直接移动头指针至当前尾指针处字符前一次的出现位置之后,总的时间复杂度是
O
(
n
)
O(n)
O(n) 。
总结一下就是双指针法。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int len=s.length();
unordered_map<char,int> m;
int i=0,j=0,res=0;
while(j<len){
if(m.find(s[j])!=m.end())
i=max(i,m[s[j]]+1);
m[s[j]]=j;
res=max(res,j-i+1);
j++;
}
return res;
}
};
暴力枚举 O ( n 3 ) O(n^3) O(n3)
- 暴力枚举的几个代码都是 TLE 的,写着玩玩
Java
class Solution {
public int lengthOfLongestSubstring(String s) {
int n=s.length();
int res=0;
for(int i=0;i<n;i++)
for(int j=i+1;j<=n;j++)
if(check(s,i,j))res=Math.max(res,j-i);
return res;
}
public boolean check(String s, int begin, int end){
Set<Character> set=new HashSet<>();
for(int i=begin;i<end;i++){
Character ch=s.charAt(i);
if(set.contains(ch))return false;
set.add(ch);
}
return true;
}
}
- 会 TLE
C++
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n=s.length();
int res=0;
for(int i=0;i<n;i++)
for(int j=i+1;j<=n;j++)
if(check(s,i,j))res=max(res,j-i);
return res;
}
bool check(string s,int begin,int end){
set<int> a;
for(int i=begin;i<end;i++){
char c=s[i];
if(a.find(c)!=a.end())return false;
a.insert(c);
}
return true;
}
};
Python
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
res = 0
n = len(s)
for i in range(n):
for j in range(i+1,n+1):
if self.check(s,i,j):
res = max(res, j-i)
return res
def check(self, s, begin, end):
m = []
for i in range(begin, end):
if s[i] in m:
return False
m.append(s[i])
return True
Go
func lengthOfLongestSubstring(s string) int {
n:=len(s)
res:=0
for i:=0;i<n;i++{
for j:=i+1;j<=n;j++{
if check(s,i,j){
if j-i>res{
res=j-i
}
}
}
}
return res
}
func check(s string, b, e int) bool {
m:=make(map[byte]bool)
for i:=b;i<e;i++{
if m[s[i]]==true{
return false
}
m[s[i]]=true
}
return true
}
双指针法 O ( n ) O(n) O(n)
Java
class Solution {
public int lengthOfLongestSubstring(String s) {
int n=s.length();
int res=0;
Map<Character, Integer> mp=new HashMap<>();
for(int j=0,i=0;j<n;j++){
if(mp.containsKey(s.charAt(j)))
i=Math.max(mp.get(s.charAt(j))+1,i);
res=Math.max(res,j-i+1);
mp.put(s.charAt(j),j);
}
return res;
}
}
- 字符的取值范围确定的话可以这样写:
class Solution {
public int lengthOfLongestSubstring(String s) {
int n=s.length();
int res=0;
int[] mp=new int[256];
for(int j=0,i=0;j<n;j++){
i=Math.max(mp[s.charAt(j)],i);
res=Math.max(res,j-i+1);
mp[s.charAt(j)]=j+1;
}
return res;
}
}
C++
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n=s.length();
int res=0;
unordered_map<char,int> mp;
for(int i=0,j=0;j<n;j++){
if(mp.find(s[j])!=mp.end())
i=max(mp[s[j]]+1,i);
mp[s[j]]=j;
res=max(res,j-i+1);
}
return res;
}
};
- 数组 map
class Solution {
public:
int mp[256];
int lengthOfLongestSubstring(string s) {
int n=s.length();
int res=0;
for(int i=0,j=0;j<n;j++){
i=max(i,mp[s[j]]);
mp[s[j]]=j+1;
res=max(res,j-i+1);
}
return res;
}
};
Python
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
res = 0
j = 0
m = {}
for i, c in enumerate(s):
if c in m:
j = max(j, m[c]+1)
m[c] = i # store where c last appears
res = max(res, i-j+1)
return res
Go
func lengthOfLongestSubstring(s string) int {
m:=make(map[rune]int)
res:=0
left:=0
for i,c:=range s{
if _,ok:=m[c]; ok==true&&m[c]>=left{
left=m[c]+1
}
res=max(res,i-left+1)
m[c]=i
}
return res
}
func max(a,b int)int{
if a>b{
return a
}
return b
}