LeetCode0003-无重复字符的最长子串
题目:
给定一个字符串,找出其中不含有重复字符的最长子串的长度
示例1:
输入:“abcabcbb”
输出:3
解释:因为无重复字符的最长子串是"abc",所以长度为3
示例2:
输入:“bbbbb”
输出:1
解释:因为无重复字符的最长子串是"b",所以长度为1
示例3:
输入:“pwwkew”
输出:3
解释:因为无重复字符的最长子串是"wke",所以其长度为3,
注意:答案必须是子串的长度,“pwke”是一个子序列,不是子串
分析(滑动窗口法)
以示例一中的字符串 abcabcbb 为例,找出 从每一个字符开始的,不包含重复字符的最长子串,那么其中最长的那个字符串即为答案。对于示例一中的字符串,我们列举出这些结果,其中括号中表示选中的字符以及最长的字符串:
- 以( a)bcabcbb 开始的最长字符串为(abc)abcbb;
- 以a( b)cabcbb开始的最长字符串为a(bca)bcbb;
- 以ab( c)abcbb开始的最长字符串为ab(cab)cbb;
- 以abc( a)bcbb开始的最长字符串为abc(abc)bb;
- 以abca( b)cbb开始的最长字符串为abca(bc)bb;
- 以abcab( c)bb开始的最长字符串为abcab(cb)b;
- 以abcabc( b)b开始的最长字符串为abcabc(b)b;
- 以abcabcb( b)开始的最长字符串为abcabcb(b).
如果依次递增地枚举子串的起始位置,那么子串的结束位置也是递增的,这里的原因在于,假设我们选择字符串中的第k个字符作为起始位置,并且得到不包含重复字符的最长子串的结束位置rk。那么当我们选择第k+1个字符作为起始位置时,首先从k+1到rk的字符显然不会重复,并且由于减少了原本的第k个字符,我们可以尝试继续增大rk,直到右侧出现重复字符为止、
这样以来,就可以使用滑动窗口来解决这个问题:
使用俩个指针表示字符中的某个子串(左右边界)。其中左指针代表上述枚举子串的起始位置,而右指针即为rk。
每一步的操作中,会将左指针向右移动一格,表示,开始枚举下一个字符作为起始位置,然后可以不断地向右移动右指针,但需要保证这俩个指针对应的子串中没有重复的字符。在移动结束后,这个子串就对应着,以左指针开始的,不包含重复字符的最长子串、记录下这个长度;
在枚举结束时,找到最长的子串长度即为答案。
Java程序实现:
import java.util.HashSet;
import java.util.Set;
/**
* 0003 无重复字符的最长子串
* 给定一个字符串,请找出其中不含重复字符的最长子串的长度
* 示例1:
* 输入:"abcabcbb"
* 输出:3
* 解释:因为无重复字符的最长子串是 "abc",所以其长度为3
* 示例2:
* 输入:"bbbbb"
* 输出:1
* 解释:因为无重复字符的最长子串是"b",所以其长度为 1
* 示例3:
* 输入:"pwwkew"
* 输出:3
* 解释:因为无重复字符的最长子串是"wke",所以其长度为3。
* 注意:答案必须是子串的长度,"pwke" 是一个子序列,不是子串。
*/
/**
* 滑动窗口法解决
*/
class Solution {
public int lengthOfLongestSubstring(String s) {
//Set集合,记录每个字符是否出现过
Set<Character> set = new HashSet<>();
// 右指针,初始化为-1,相当于在字符串的左边界的左侧,还没开始移动
int rightK = -1;
// 保存需要返回的结果(最长的无重复子串)
int result = 0;
// 通过循环,遍历所有的字符作为开始位置的最长子串
for (int i = 0; i < s.length(); i++) {
if (i != 0) {//表示set集合中有元素,才可以执删除前一个位置的元素
// 删除前一个位置的元素,相当于移动滑动窗口的左指针
set.remove(s.charAt(i - 1));
}
// 移动滑动窗口右指针的操作
// 第一个条件判断,字符串是否还有长度,即,右指针移动操作是否合法
// 第二个条件,判断右指针向右移动一位,该字符加入set中是否合法
// boolean contains(Object o);判断该set中是否还有 o 元素,有则返回true,
while (rightK + 1 < s.length() && !set.contains(s.charAt(rightK + 1))) {
// 滑动窗口右指针移动,将该合法的元素加入set集合
set.add(s.charAt(rightK + 1));
rightK++;
}
//result最大值判定
result = result > rightK - i + 1 ? result : rightK - i + 1;
}
return result;
}
}
/**
* 测试类
*/
public class Study0003 {
public static void main(String[] args) {
System.out.println(new Solution().lengthOfLongestSubstring("abcabcbb"));
}
}