题目大意:
给定一个字符串str,求该字符串中的最长无重复子串的长度。
如“abcd”的最长无重复子串是“abcd”,长度为4;“abcb”的最长无重复子串是“abc”,长度为3。
题目思路:
遍历字符串,表示出以每个字符串元素str[i]为结尾的最长无重复子串长度,遍历完成后求最大值即可。
如何求以str[i]为结尾的最长无重复子串长度呢?
1、得到以str[i-1]为结尾的最长无重复子串长度pre,获取对应最长无重复子串的起始索引值,记为lastleft;
2、通过map[str[i]] 得到当前元素上一次出现的位置(即位置在当前元素左边的重复元素),取该位置索引值加1,记为nowleft。
如果nowleft>lastleft,当前元素的最大无重复子串的起始位置只能取nowleft,不然再往左取一位就会取到该元素的重复值。
如果nowleft<lastleft,当前元素的最大无重复子串的起始位置只能取lastleft,不然再往左取一位就会取到该元素前一位元素的重复值。
总结出来,当前元素的最大无重复子串的起始位置取得是nowleft和lastleft的最大值。
3、更新以当前元素为结尾的最大无重复子串长度pre,以及当前元素最近一次的出现位置map[str[i]]为当前位置。
遍历字符串str的同时维护一个map数组和pre变量,其中:
map数组:数组各值初始化为-1,mymap[i]存储str[i]在字符串中上一次出现的位置.
pre变量表示以str[i-1]为结尾的最大无重复子串长度。
如果nowleft<lastleft:
如果nowleft>lastleft:
nowleft 和lastleft相等时,取任意一个即可。
代码实现:
class DistinctSubstring {
public:
int longestSubstring(string A, int n) {
// write code here
int mymap[300];//表示当前元素上一次出现的index,如果之前没出现过就没有这个关键词;
int pre = 0,index = 0;//index 表示以当前元素为结尾的最长无重复子序列的起始位置。
int maxnum = 0;
memset(mymap,-1,sizeof(mymap));
for(int i = 0;i<n;i++){
if(mymap[A[i]]!=-1)//之前出现过该元素
{
int lastleft = i-pre;
int nowleft = mymap[A[i]]+1;
index = nowleft;
if(lastleft>nowleft)
index = lastleft;
mymap[A[i]] = i;
pre = i-index+1;
}
else{
mymap[A[i]] = i;//记录下来
pre++;
}
if(pre>maxnum)
maxnum = pre;
}
return maxnum;
}
};
注意点:str[i] 对应着ascii码,因此可以直接作为map的索引值。