文章目录
- 无重复字符的最长子串
- ⛅前言
- 🔒题目
- 🔑题解
无重复字符的最长子串
⛅前言
大家好,我是知识汲取者,欢迎来到我的LeetCode热题100刷题专栏!
精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。在此专栏中,我们将会涵盖各种类型的算法题目,包括但不限于数组、链表、树、字典树、图、排序、搜索、动态规划等等,并会提供详细的解题思路以及Java代码实现。如果你也想刷题,不断提升自己,就请加入我们吧!QQ群号:827302436。我们共同监督打卡,一起学习,一起进步。
博客主页💖:知识汲取者的博客
LeetCode热题100专栏🚀:LeetCode热题100
Gitee地址📁:知识汲取者 (aghp) - Gitee.com
Github地址📁:Chinafrfq · GitHub
题目来源📢:LeetCode 热题 100 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台
PS:作者水平有限,如有错误或描述不当的地方,恳请及时告诉作者,作者将不胜感激
🔒题目
原题链接:3. 无重复字符的最长子串 - 力扣(LeetCode)
🔑题解
-
解法一:滑动窗口算法
看到这个题目,我第一个想法就是使用滑动窗口算法😄,简单粗暴
滑动窗口算法主要思路:
-
Step1:构建窗口。定义两个变量
l
和r
(这两个变量就相当于是“指针”),l 确定窗口左边界,r 确定右边界,这样就构成了一个由 l 和 r 的窗口 -
Step2:滑动窗口。
- 使用 r 往右遍历字符串
- 在遍历的过程中需要判断新加入窗口的元素是否与已窗口中的元素发生重复
- 如果重复了,就需要不断移动 l,直到不重复为止
不断执行1、2、3步,这样我们的窗口就滑动起来了。其中2是核心步骤,一般我们可以通过Set或者Map集合进行判断(当然也可以使用其它方法进行判断,比如数组、字符串,但这两个方法是比较主流的,如何选择就看个人爱好和习惯)
思路还是挺简单的,可以看一下下面的示意图:
import java.util.HashSet; import java.util.Set; /** * @author ghp * @title 无重复字符的最长子串 */ class Solution { public int lengthOfLongestSubstring(String s) { if (s.length() == 0) { return 0; } // 使用Set集合记录加入窗口的元素(Set集合无重复、插入和删除比较快) Set<Character> set = new HashSet<>(16); int max = Integer.MIN_VALUE; int l = 0; // 窗口左边界 int r = 0; // 窗口右边界 while (r < s.length()) { // 移动右边界,往窗口中添加新元素 char ch = s.charAt(r++); while (set.contains(ch)) { // 新加入窗口的元素与已有元素发生重复,移动左边界 set.remove(s.charAt(l++)); } // 新元素没有与窗口中已有元素发生重复,加入set集合 set.add(ch); // 获取当前最大 无重复字符的最长子串 的长度 max = Math.max(max, r - l); } return max; } }
复杂度分析:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
其中 n n n 为数组中元素的个数
这里还提供几种其它方式来判断元素是否重复的方式:
直接使用String自带的
contains
方法,需要注意的是sbustring
方法截取的是包前不包后class Solution { public int lengthOfLongestSubstring(String s) { if (s.length() == 0) { return 0; } int max = Integer.MIN_VALUE; int l = 0; int r = 0; while (r < s.length()) { // 移动右指针,往窗口中添加新元素 String ch = s.charAt(r++) + ""; // 判断新增元素是否与窗口中已有元素发生重复,重复就移动左指针,直到不重复为止 while (s.substring(l, r-1).contains(ch)) { l++; } // 获取当前最大 无重复字符的最长子串 的长度 max = Math.max(max, r - l); } return max; } }
-
-
解法二:官方提供的方法,好像也是滑动窗口算法🤣,此外官网并没有提供其它解法,所以说这类题型虽然存在其它解法,但是滑动窗口算法肯定是最优的了
class Solution { public int lengthOfLongestSubstring(String s) { // 哈希集合,记录每个字符是否出现过 Set<Character> occ = new HashSet<Character>(); int n = s.length(); // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动 int rk = -1, ans = 0; for (int i = 0; i < n; ++i) { if (i != 0) { // 左指针向右移动一格,移除一个字符 occ.remove(s.charAt(i - 1)); } while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) { // 不断地移动右指针 occ.add(s.charAt(rk + 1)); ++rk; } // 第 i 到 rk 个字符是一个极长的无重复字符子串 ans = Math.max(ans, rk - i + 1); } return ans; } } 作者:LeetCode-Solution 链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
其中 n n n 为数组中元素的个数