题干:
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abcabcbb"
, the answer is "abc"
, which the length is 3.
Given "bbbbb"
, the answer is "b"
, with the length of 1.
Given "pwwkew"
, 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.
解法一:
列出所有字符串,并判断是否有重复字符。(最直观的方法,但是运算量极大,不要用)
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int ans = 0;
for (int i = 0; i < n; i++)
for (int j = i + 1; j <= n; j++)
if (allUnique(s, i, j)) ans = Math.max(ans, j - i);
return ans;
}
public boolean allUnique(String s, int start, int end) {
Set set = new HashSet<>();
for (int i = start; i < end; i++) {
Character ch = s.charAt(i);
if (set.contains(ch)) return false;
set.add(ch);
}
return true;
}
}
解法二:
利用HashSet做划窗来判断字符唯一性。(用这个)
public class LengthOfLongestSubstring3 {
/*
* 思路:
* 用Set做一个范围为 [i,j)的划窗(利用Set检查char的唯一性)。
* 在确定s[i,j-1]没有重复字符的情况下,只需检查s[j]是否存在于s[i,j-1]中就可以了。
* 如果s[j]存在于s[i,j-1]中,那么划窗变为 [i+1,j),继续检查。
*
**/
public int lengthOfLongestSubstring(String s) {
int n = s.length();
Set set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {
// try to extend the range [i, j]
if (!set.contains(s.charAt(j))) {
// 此处是根据角标j来遍历,一个一个的往里存
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);//注意这里为什么是j-1而不是j-i+1呢?因为j已经++了
} else {
set.remove(s.charAt(i++));
}
}
return ans;
}
}
思考:整个流程中,角标是如何变化的?以及while(i 解法三: 利用HashMap建立{字符-索引}的映射,降低找重复时的时间复杂度(优解但是不太好想) 思考:怎么用一次循环完成整个算法的?想清楚整个流程中两个索引i,j是怎么变化的。 *注意max*
public class Solution {
/*
* 思路: 使用HashMap存放{字符-索引}的映射,当我们发现重复的字符时,直接跳过这些字符。
* 通过遍历j来循环。如果遍历到j时,s[i,j)中有重复元素s[j],我们不再一点一点移动i的位置了,
* 若重复元素角标为j',直接跳过[i,j′]这个区间即可,直接将i赋值为j'+1。
*
*/
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
// Hashmap中存放的是 字符-索引
Map