携手创作,共同成长!这是我参与「掘金日新计划 · 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开始。
当右边界在字符串内且右边界所在字符不在去重数组中,则将此字符放入去重数组中,然后右边界向右移动;
当右边界不满足条件,则对长度进行计算,并且将左边界在数组中的值清空,因为下一次循环左边界要向右滑动一位。
代码实现
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;
}