题目:
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abcabcbb"
, the answer is "abc"
, which the length is 3.
Given "bbbbb"
, the answer is "b"
, with the length of 1.
Given "pwwkew"
, 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.
分析:
也就是找不含重复字母的子串的最大长度。可以用滑动窗口的思想,每个窗口有一个start位置,窗口长度可以随着遍历增长;按顺序一个个字母移动,如果第i个字母已经在从start到i的子串中出现了,那么可以计算从start--> i-1位置的长度,如果足够大,即保存为最新的maxlength;并且窗口要向下滑动,以第i个字母在子串中出现过的位置的下一个作为新的start;如果遍历的是没出现过的字母,计算当前子串的长度,检查是否要更新maxlength
举个例子,abac ,一开始start设为0,maxlength设为0,开始遍历,第一个到'a',从没有出现过,当前子串长度为1,更新'a'上次出现的位置为索引0;i=1时遍历到‘b’,也没出现过,子串现在长度为2;i=2时字母‘a’,上次出现的位置是0处,在当前判断的子串范围内(0-2),所以start要变成1(滑动窗口向下滑动,过滤掉开始的字母'a');继续i=3,此时计算从start位置开始的子串长度为3
那么怎么快速查看当前字母是否在当前滑动窗口所含子串里呢?可以用map<char,int>,记录字母char上次出现的位置,然后与start比较,是否是在当前考虑的子串中
代码:
int lengthOfLongestSubstring(string s) { map<char,int>mapp; int length = s.length(); int start = 0;int maxlen = 0; for(char i = 'a';i<='z';i++)mapp[i]=-1;//初始化,只初始化小写字母也过了,可能是样例不含大写字母 for(int i = 0;i<length;i++) { if(mapp[s[i]]>=start)//当前遍历到的字母在现在考虑的子串中出现过了 { start = mapp[s[i]]+1;//start设为出现过的那一字母的下一位置,也就是过掉重复字母 mapp[s[i]]=i;//记录该字母出现的位置为下一次所用 } else{//没出现过 mapp[s[i]]=i;//记录出现的位置 int t = i-start+1;//记录目前从start位置开始的子串长度 maxlen = (maxlen<t)?t:maxlen; } } return maxlen; }
几个样例:
abcabcbb
abcabc
a
ab
aab
tmmzuxt