版权声明:本文为博主原创文章,转载联系 [email protected] https://blog.csdn.net/qq_31573519/article/details/82501033
1. 暴力穷举遍历(慢)
/**
* #3
* 无重复最长字符子串
* https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/description/
* @param s
* @return
*/
/** 方法一:暴力遍历 **/
public int lengthOfLongestSubstring (String s){
// 获取原始字符串的长度
int n = s.length();
// 初始化为结果的长度为0
int ans = 0;
// 暴力遍历,定义2个游标,第一个游标从0位置开始,2个游标之间最短距离就是一个字符长度,那么j就应该从i+1开始
for (int i = 0; i < n; i ++){
for (int j = i + 1; j <= n; j ++){
// 调用allUnique函数,allUnique函数会判断在每一次的字符子串遍历中,是否包含该单个字符
if (allUnique(s, i, j)) { ans = Math.max(ans, j - i);}
}
}
return ans;
}
public boolean allUnique(String s, int start, int end){
// 定义一个Set集合,存储判断过的字符
Set<Character> set = new HashSet<Character>();
// 在开始和结束的下标之间,遍历下标获取字符串中的单个字符
for (int i=start; i<end; i++){
// 一边遍历,一边判断 set集合中是否已经包含当前获得的字符,如果判断到了包含,那么说明字符已经开始重复
if (set.contains(s.charAt(i))){
return false;
}
set.add(s.charAt(i));
}
// 最坏的情况下,在start和end的范围内,每个字符都不包含,那么直接return true
return true;
}
2. 滑动窗口
/** 方法二:滑动窗口 **/
public int lengthOfLongestSubstringSlidingWindow (String s){
// 初始化定义返回结果,原始字符串长度,遍历游标
int n = s.length(), ans = 0, i = 0, j = 0;
// 定义存储单个字符的 HashSet(无序不重复)
Set<Character> set = new HashSet<Character>(n);
// 在 i、j都在 n的范围内进行从左向后的遍历
// 可以想象为有一个窗口,在一个字符串上进行从左向右的滑动
// 初始状态下,这个窗口是一个[i,j),左闭,右开的范围
// 然后 i、j 依次开始累加,要么左区间向右移动一格,要么右区间向右移动一格,依次向后
// 所以最坏的情况下,每个元素都被i和j访问2次,复杂度为 O(2n) = O(n)
while (i < n && j < n){
// 判断窗口右端的值是否在Set中,如果不在,那么把元素塞到Set里,形象到窗口中就是右区间向右移动一格
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;
}