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.
题目分析:求没有重复字符的最长子字符串的长度
算法分析:
1、蛮力法:最直白的,构造函数 boolean allUnique(String substring),逐一迭代,判断是否重复。
2、Sliding Window (滑动窗口)法:鉴于蛮力法的时间复杂度是三次方,非常之慢,提交后Time Limit Exceeded,显然不够合适。仔细分析,在蛮力法中,我们重复地去判断字符是否重复,但是这是不必要的,如果说子串中 i —> j-1 处都不是重复的字符,那么只需要判断 j 处的字符是否 已经在子串中,此时只需要遍历子串。这里提出一个Sliding Window (滑动窗口)法,同时使用HashSet。
在 array或者string问题里,Sliding Window (滑动窗口)法是一个抽象的概念。窗口是通过区间来定义的,比如说 [ i , j) 左闭右开,滑动窗口就是按照特定的方向来访问元素的意思,如果向右以1个元素的方式滑动,窗口就变为 [ i +1 , j + 1) 左闭右开。在本题中,在当前窗口[ i , j),我们用HashSet存放字符,将 j 向右滑动,直到HashSet 中已经有 s [ j ] ,注意,j 的初值是i,也就是从 j=i 开始滑动的,如果对每个 i 都这样做,也就找到了答案。
3、Sliding Window (滑动窗口)法再优化:上一个方法最多需要2n步,其实可以再优化为n步。我们可以定义一个字符下标的HashMap,这样,如果现在 判断 出 j 处的字符是重复的,就可以直接跳过 [ i , j ] 中的元素,让 i = j +1,而不是对每个 i 操作,使其增加。
算法设计:
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<Character> 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;
}
}class Solution { // Sliding Window (滑动窗口)法
public int lengthOfLongestSubstring(String s) {
int n = s.length();
Set<Character> set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {
if (!set.contains(s.charAt(j))){
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);
}
else {
set.remove(s.charAt(i++));
}
}
return ans;
}
}class Solution { // Sliding Window (滑动窗口)法再优化
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
Map<Character, Integer> map = new HashMap<>();
for (int j = 0, i = 0; j < n; j++) {
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)), i);
}
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j + 1);
}
return ans;
}
}
本文探讨了寻找字符串中最长无重复字符子串的有效算法,包括蛮力法、滑动窗口法及其优化版本。通过逐步分析,展示了如何将时间复杂度从三次方减少到线性。

被折叠的 条评论
为什么被折叠?



