开启掘金成长之旅!这是我参与「掘金日新计划 · 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,这时候不满足要求。所以,我们要移动这个队列!
如何移动?
我们只要把队列的左边的元素移出就行了,直到满足题目要求!
一直维持这样的队列,找出队列出现最长的长度时候,求出解!
代码:
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 在合适的时候移动指针,并能轻松的解决该题
好了,本篇文章到这里就结束了,感谢你的阅读🤝