描述
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.思路
首先想到使用暴力解法,即使用每个字母作为开始,分别计算当前字母的最长不重复子串。从这些最长串长度中选择最长的串。
对于最长不重复子串的记录使用HashSet,使用size()函数确定当前串的长度。
class Solution {
public int lengthOfLongestSubstring(String s) {
int maxLen = 0;
for(int i = 0;i<s.length();i++){
int thisLen = 0;
Set<Character> temp = new HashSet<Character>();
for(int j = i;j<s.length();j++){
if(temp.contains(s.charAt(j))){
break;
}else if(s.charAt(i) != s.charAt(j)){
temp.add(s.charAt(j));
}else if(j == i){
temp.add(s.charAt(j));
}else{
break;
}
}
thisLen = temp.size();
maxLen = (thisLen>maxLen?thisLen:maxLen);
}
return maxLen;
}
}可以暴力AC,但是时间复杂度和空间复杂度都不是很好。
优化
看到问题讨论区有使用map作为字符串出现记录工具的,这个代码很巧妙的解决了去重的问题,并且只用遍历一遍数组。经典的KMP算法也是避免反复对字符串进行比对,两者有异曲同工之妙。
the basic idea is, keep a hashmap which stores the characters in string as keys and their positions as values, and keep two pointers which define the max substring. move the right pointer to scan through the string , and meanwhile update the hashmap. If the character is already in the hashmap, then move the left pointer to the right of the same character last found. Note that the two pointers can only move forward.
public int lengthOfLongestSubstring(String s) {
if (s.length()==0) return 0;
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
int max=0;
//使用i,j下标指示器,j作为收尾指针,i作为开头指针
//j = Math.max(j,map.get(s.charAt(i))+1)巧妙的保证i,j所含的区域没有重合的字符
for (int i=0, j=0; i<s.length(); i++){
if (map.containsKey(s.charAt(i))){
j = Math.max(j,map.get(s.charAt(i))+1);
}
//将打头的i指向的字符做记录
map.put(s.charAt(i),i);
max = Math.max(max,i-j+1);
}
return max;
}可以看到时间复杂度大幅提高。
在进行字符串比对时要注意看看有没有可能不让指针回退,可以大幅提高效率。