LeetCode0003-无重复字符的最长子串

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"));
    }
}


结果:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值