【中等】3-无重复字符的最长子串 Longest Substring Without Repeating Characters
题目
Given a string, find the length of the longest substring without repeating characters.
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
Example1
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
Example2
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
Example3
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
来源:力扣(LeetCode)
链接:https://leetcode.com/problems/longest-substring-without-repeating-characters
解题思路
p.s. 字符串S[i:j]表示从字符S[i]开始到S[j]截止(不包括S[j])的子字符串
首先,看到这道题第一想法仍然是暴力过程:从每一位开始,向后查找到使得区间没有重复字符的最大位置截止,即为一个无重复字符子串,最后得到的最大长度就是问题的解。当然,很明显这种方法是十分复杂不可取的。
此时,我们分析是什么过程使得暴力过程如此复杂?假设从第i位开始,依次检查重复字符,发现到第j位都没有重复字符,而第j+1位上出现了与第t位重复的字符(i<=t<=j),按照暴力破解流程,我们将从第i位开始的最长子串大小设置为j-i+1,然后又从第i+1位开始重复上述查询过程。
这时,出现了第一个重复的检查过程:第i+1到第j位上明显是没有重复字符的,如果再次进行比较就是多余的过程,所以,只需要检查第j+1位在字符串[i+1:j+1]上是否有重复字符即可
此时第二个重复过程也出现了:j+1位在子串[i+1:j+1]上是否重复这个结果我们已经知道了,即如果i=t,那么没有重复,如果t>i,那么自然在第t位上与j+1位重复,同理,从第i+1到第t位的计算过程都是可以省略掉的。
随之第三个重复过程就是,在子串[t+1:j+2]中一定没有重复子串,所以后续检查j+2位在子串[t+1:j+2]中是否有重复子串即可
也就是说,如果已知子串[i:j+1]是字符串的无重复子串,而第j+1位与第t位发生重复,那么对于i+1到t,无论从哪一位开始作为无重复子串的起始位,都没有办法得到一个长度大于j-i+1的字符串,因为一定会同时包含t位和j+1位,如果想要找到后续的字符串,只能从第t+1位开始算起,又因为第t+1位到第j+1位一定没有重复字符串,所以只需要从j+2位继续检查的过程。
这也是常说的滑动窗口
由此我们得到这道题的算法:
对于一个字符串s
,初始化开始位置为0,查询位置为1,长度为1,已知子串窗口为s[0:1]
,依次检查待检查位与子串窗口是否有重复字符,如果一直到第j位都没有重复字符,字串逐步更新为s[0:j+1]
(扩大子串长度),最大长度为l;如果在第t位有重复,则开始位置设置为t+1,待检查位为j+2,重复上述过程
代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.length() <= 1) return s.length();
int max = 1;
int last = -1;
for(int i = 1; i < s.length(); ++i){
for(int j = last+1; j < i; ++j){
if(s[i] == s[j]){
last = j;
}
}
max = max < i-last ? i-last : max;
}
return max;
}
};