一道挣扎了两天的题[罪过.jpg]
从内存超限到时间超限再到答案错误到最后的答案正确【当然期间看了下别人的代码与提示】,自己用了贪心,解决了时间超限问题,最后再提交的过程中弥补了自己算法的不足~
题目:
Given a string, find the length of the longest substring without repeating characters.
Example 1:
Input: "abcabcbb"
Output: 3
Explanation: The answer is "abc"
, with the length of 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: The answer is "b"
, with the length of 1.
Example 3:
Input: "pwwkew"
Output: 3
Explanation: The answer is "wke"
, with the length of 3.
Note that the answer must be a substring, "pwke"
is a subsequence and not a substring.
题目大意就是求没有重复字符串的最长子串。
开始的时间超限的思路:先用双层for循环求子串,在双层循环中调用判断子串中是否有重复字符的函数,当然最后悲剧了,虽然我让循环次数尽可能的少了,但。。。。
所以开始改尽自己的方法,开始的时候认为是自己调用的函数不够精简,又去学习了下C++的容器有关的知识,用map对象又写了一个求字符串中是否有重复字符的函数,依然未能成功。最后琢磨了下别人的代码,知道有简单的方法,但是自己不太理解,后来找了下别人的思路,知道他用了滑动窗口的理念,所以又自己重新思考了下,以至最后解出此题。
思路:题目要求的是连续的无重复的最大子串长度,所以可以假设一个窗口初始的大小为0,在遍历题目所给字符串的时候,若此字符在你所记录的起始位置到此时遍历的位置中没有重复出现,就扩大窗口长度,每次更新max值。若出现过,则从上次出现过的位置的下一位开始重新求无重复的子串长度,并计数更新max值。
现在借助一些变量来理解我的思想。
int first = 0 ; //记录你现在子串的起始位置(并不一定表示最长子串的起始位置)
int max = 1 ; //最后所求的子串长度最大值(前面为0的情况我直接返回了,所以这里设为1)
int count = 0 ; //记录从first开始的无重复字符的子串可延伸的长度,即现在窗口的最大长度
int score[300] ; //score[k] = x 表示为 score[s[i]] = 上一次出现字符s[i]的位置x,用此数组来查看该字符是否重复出现。初值为-1(因为记录字符出现过的位置,所以取任意负值均可)
1、遍历string s[i] ,起始的时候first在下标0处,即从0开始让窗口尽可能的大,若访问一个字符s[i]时,上一次出现过的位置score[s[i]] == -1(即从first开始未出现过)则更新s[i]所在的位置,并且长度+1,即count++,并让max=max(max,count)
2、上一步解决从first开始后未出现过字符的情况,那接下来考虑的是:当遍历到s[i]时,s[i]在之前已经出现过,即
score[s[i]]!=-1 ,那么此时 first就要从上一次出现s[i]的下一个位置开始,并且count要重新计数,当然first变更之后,变更前后之间的字符位置要归为-1,以便后面重新计数,查找下一个子串。并且i是每次+1的,此次因为s[i]出现过,first滑倒了上次s[i]出现位置的下一位,也就是score[s[i]]现在为-1,所以此时的做法是将i-1,让其更新s[i]的位置。
其实重要的是几个初始变量的意义,剩下的可以看代码理解,此题主线是字符串连续不跳跃,可用贪心
附C++代码:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.length() == 0) return 0 ;
//贪心;滑动窗口,以至窗口长度最大;
int first = 0 ;
int max = 1 ;
int count = 0 ;
int score[300] ;
for(int i = 0 ; i < 300 ; i++) //score[k] = x ==> score[s[i]] = 上一次出现的位置x
score[i] = -1 ;
for( int i = 0 ; i < s.length() ; i++){
if(score[s[i]] == -1){
score[s[i]] = i;
count ++;
if(count > max)
max = count ;
}
else{
for( ; first <= score[s[i]] ; first++)
score[s[first]] = -1 ;
count = i - first ;
i-- ; //由于没走if,此时的s[i]位置没被更新,所以-1,重新赋值
}
}
return max ;
}
};