leetcode题库第三题---无重复字符的最长子串
这道题是要求我们求出一个字符串中最大的子串长度,并且这个子串还要满足没有重复字符。
题目要求中最重要的是子串这个概念。子串是从原串上截取的一段,一定是连续的。
这道题运用到了滑动窗口的方法。滑动窗口的思想就是,我们维护一个滑动窗口,保证这个窗口中的字符各不相同,这个窗口是由一个start指针和end指针构成的。
start,end均指向源字符串。每次我们移动end指针,我们会判定end指针指向的字符是否在这个窗口中出现过,如果出现过,那么我们需要更新start指针,start指针更新为滑动窗口中出现过字符的下一个字符的下标。然后将end指针指向的字符添加到滑动窗口中。如果end指针指向的字符不在这个窗口中,那么直接将字符添加到滑动窗口中。这个循环过程中,滑动窗口是一个变化的窗口,变化的是它里面的字符,变化的是它窗口的长度。不变的是窗口中的字符必定不是重复的。那么我们要求无重复字符的最长子串的长度,就是这个变化过程中,滑动窗口的最大值!!
滑动窗口的的长度怎么算?不就是end-start+1嘛。那么result = max(result,end-start+1)
但是从上面的描述中,重点是怎样判定新字符是否在窗口中出现过。
很简单,每次我们遍历的时候,遍历到一个字符,我们就将这个字符添加到一个set中。每次遇到一个新字符,就判定这个set里面有没有这个字符。但是有一个问题,这个set里面是从源字符串开始遍历的时候,经过的所有字符集合,而非当前滑动窗口中的字符集合!所以这个集合是无法起到效果的。
那么这个算法中最妙的地方就来了。我们采用map这个数据结构。每次遍历的时候,遇到一个新字符,如果这个字符在这个map中没有出现过,就将这个字符和它的下标加一的值组成的的pair添加到map中;如果出现过,我们就将更新start指针。start = max(start,mymap[s[end]])是下面代码中的更新语句。这个语句的作用如下:首先这个map是从遍历开始遇到的所有字符,它并不能起到上面所说的只判定滑动窗口中出现的字符。那么这就分两种情况,如果出现过,不是在滑动窗口中的,那么mymap[s[end]]<=start,无法对滑动窗口进行更改。如果是在滑动窗口中出现过,那么mymap[s[end]]>start,成功更新!!
下面是详细代码:
int MaxLength(string s) { int start = 0; int end = 0; map<char, int> mymap; map<char, int>::iterator it; int len = s.size(); int maxlen = 0; while (end<len) { cout<<s[end]<<endl; int times = mymap.count(s[end]); if(times==1){ it = mymap.find(s[end]); start = max(it->second,start); mymap[s[end]] = end+1; }else{ mymap.insert(make_pair(s[end],end+1)); } maxlen = max(maxlen,end-start+1); end++; } return maxlen; }
做这个题,还复习了其他的一些知识点:
c++中map对象的重要函数:find(key),返回一个迭代器。count(key)返回Key是否出现,返回值为0或1,1代表出现,0代表没有出现。
c++中字符串的遍历:
for(int i=0;i<s.size();i++){ cout<<s[i]<<endl; }