无重复字符的最长子串

95 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

一、题目描述

这是 LeetCode 热题 HOT 100 上第三题:无重复字符的最长子串,难度为 中等

Tag:「哈希表」、「数组」、「滑动窗口」

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

1、0 <= s.length <= 5 * 104

2、s 由英文字母、数字、符号和空格组成

二、解题思路

暴力解法时间复杂度较高,会达到 O(n^2),故而采取滑动窗口的方法降低时间复杂度

什么是滑动窗口?

其实就是一个队列,比如下图中的 dvdf,进入这个队列(窗口)为 dv 满足题目要求,当再进入 d,队列变成了 dvd,这时候不满足要求。所以,我们要移动这个队列!

如何移动?

我们只要把队列的左边的元素移出就行了,直到满足题目要求!

一直维持这样的队列,找出队列出现最长的长度时候,求出解!

image-20221210215201969.png

代码:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s.length()==0) return 0;
      	//定义一个 map 存储,其中 key 值为字符,value 值为字符位置 +1,加 1 表示从字符位置后一个才开				//始不重复
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        int max = 0;
        int left = 0;
        for(int right = 0; right < s.length(); right++){
            //如果存在相同的 key ,则 left 往右移动
            if(map.containsKey(s.charAt(right))){
                left = Math.max(left,map.get(s.charAt(right)) + 1);
            }
            map.put(s.charAt(right),right);
            //每次比较并获取最大无重复字符子串
            max = Math.max(max,right-left+1);
        }
        return max;
        
    }
}

时间复杂度和空间复杂度分析:

时间复杂度:O(n),其中 n 是字符串的长度。左指针和右指针分别会遍历整个字符串一次

空间复杂度:O(|Σ|),其中 Σ 表示字符集(即字符串中可以出现的字符),|Σ| 表示字符集的大小。在本题中没有明确说明字符集,因此可以默认为所有 ASCII 码在 [0, 128) 内的字符,即 |Σ| = 128。我们需要用到哈希集合来存储出现过的字符,而字符最多有 |Σ| 个,因此空间复杂度为 O(|Σ|)。

三、总结

本道算法题难度中等,主要考察了我们对滑动窗口的掌握,定义好左右指针,结合 map 在合适的时候移动指针,并能轻松的解决该题

好了,本篇文章到这里就结束了,感谢你的阅读🤝