leetcode刷题日记-【3. 无重复字符的最长子串】

56 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

题目描述

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

 

示例 1:

输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 示例 2:

输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 示例 3:

输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。   请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。  

提示:

0 <= s.length <= 5 * 104 s 由英文字母、数字、符号和空格组成

题目要素

  • 字符串s包含数字、英文、符号、空格等。

  • 需要在s中寻找到最长的不重复的字符串长度。

解题思路

这道题乍一看和leetcode5有点像,但是区别也挺大。首先这个问题可以拆解成小问题吗?i,j间的字符串是非重复的,那i+1,j-1间的字符串也一定是非重复的。

但是区别就是i,j是否是重复的不是只取决于i+1,j-1间字符串是否重复和i,j位置上的字符是否一致。所以这道题没办法进行拆解。

那解决这种问题的方法,就是滑动窗口了。什么是滑动窗口呢?就是将字符串下标作为窗口的左右边界,假定左边界不变,满足条件的话右边界就向右移动;当不满足条件,就将左边界向右移动,再依次移动右边界。循环往复,求得最大不重复的字符串长度。

解题步骤

左边界从0开始,右边界也从0开始。

当右边界在字符串内且右边界所在字符不在去重数组中,则将此字符放入去重数组中,然后右边界向右移动;

当右边界不满足条件,则对长度进行计算,并且将左边界在数组中的值清空,因为下一次循环左边界要向右滑动一位。

image.png

代码实现

public int lengthOfLongestSubstring(String s) {
    // 不重复的最长字串--没办法判定i,j所处的字符是否与[i+1,j-1]之间的字符是否相等,所以没办法将问题进行拆解
    // 首先确定存储结构,用来存储不重复的数据,所以可以使用set,也可以用hashmap来存储,然后再判断一下。
    Set<Character> appearChars = new HashSet<>();
    // 滑动窗口
    int maxLength = 0;
    char[] chars = s.toCharArray();
    // 循环遍历右边界
    int right = 0;
    for (int i =0;i< chars.length;i++) {
        if (i > 0){
            // 左边界向右滑动(移除之前左边界元素的值)
            appearChars.remove(chars[i-1]);
        }
        while (right < s.length() && !appearChars.contains(chars[right])) {
            // 右边界小于字符串长度 且 右边界字符不在之前的字符串内
            appearChars.add(chars[right]);
            right ++ ;
        }
        maxLength = Math.max(maxLength,right-i);
    }
    return maxLength;
}