码迷,mamicode.com
首页 > 其他好文 > 详细

Longest Substring Without Repeating Characters

时间:2017-02-05 13:54:06      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:简单   去重   改变   判断   访问   char   turn   span   不重复   

第三道题,和前面的那个第一道题数组里面的两个元素求和有点像,题目如下:

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.

大致意思就是,输入一个string,找到在这个string中最长的一个substring满足在这个substring中没有重复的字符,返回这个substring的长度

比如给出abcabcbb这个字符串,abc就是最长的没有重复字符的字符串,最终返回的结果就是3.

一开始,想到的办法是使用一个循环遍历字符串,使用hashmap记录没有重复的连续的字符和它们对应的在字符串中的下标位置,每一次循环都判断当前访问的元素是否已经存在在hashmap中,如果不存在,则把这个新的元素和它的下标加到hashmap中,如果存在,表示重复了,这时候循环就需要从这个重复元素在hashmap中的下标的下一个元素重新开始,同时需要把hashmap清空。

在用上面的思路写完代码以后,在测试集测试的过程中在面对像abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz这样的很长的而且不断按照同一个字符子串循环的就会出现Time limit的错误,就按照上面的字符串来说,当遍历到第二个子字符串abc..的a的时候会和前面已经放在hashmap中的位于第一个子字符串的a重复,这时候,进行的操作就是清空hashmap的同时把遍历指针放到第一个子字符串的b的位置重新开始,而上面的情况在重新遍历到第二个子字符串的b的位置的时候又会发生,这样不断循环重复遍历,实际上最大的不重复子串的长度是没有发生改变的,也就是后面进行的操作都是无用工,如果假设总字符串长度是m,存在的循环子字符串的长度是n,这时候的开销大概是m*n。

上面的这种思路使用javascript来描述:

 1 var lengthOfLongestSubstring = function(s) {
 2   var pattern={};
 3   var i=0;
 4   var longest_length=0;
 5   var length=0;
 6   while(i<s.length){
 7       if(s[i] in pattern){
 8           var dul_index=pattern[s[i]];
 9           i=dul_index+1;
10           pattern={};
11           length=0;
12       }
13       else{
14           pattern[s[i]]=i;
15           i++;
16           length++;
17           if(length>longest_length){
18               longest_length=length;
19            }  
20         }
21       }
22   }
23   return longest_length;
24 };                        

 

解决这个问题,改进上面的思路,加了一个判断位,如果当前的元素在hashmap中,不着急去重新遍历,而是继续访问下一个元素,如果下一个元素也存在在hashmap中,表示这时候重新访问只会增加开销,早晚都会碰到重复,而且得到的长度肯定比之前的短,这样的元素应该跳过,而不是在不断的重复访问,同时要记录这些连续在hashmap中存在的元素对应的下标中最大的那个,这样一旦碰到一个不在hashmap中的元素,遍历指针就只需要跳回到最大的重复元素下标的位置就行了,举个简单的例子,比如abcabcef,在访问到第四个a的时候发现和已经在hashmap中的第一个a重复,按照之前的做法,指针会直接跳回到位于第二个位置的b重新循环,改进后会继续访问位于第五个位置b,发现这个b也已经存在在了hashmap,而且这个b在hashmap中的位置2比之前记录的a在hashmap中的位置1靠后,所以更新记录b在hashmap中的位置,继续访问,c同样存在而且位置3比b靠后2,更新记录c的位置,e不存在在hashmap中,这时候跳回从记录的第三个c的下一个元素也就是第四个a重新遍历。

改进后的用javascript描述:

 1 var lengthOfLongestSubstring = function(s) {
 2   var pattern={};
 3   var i=0;
 4   var longest_length=0;
 5   var length=0;
 6   var exist=-1;
 7   while(i<s.length){
 8       if(s[i] in pattern){
 9           var dul_index=pattern[s[i]];
10           exist=exist<dul_index?dul_index:exist;
11           i++;
12       }
13       else{
14           if(exist!==-1){
15               i=exist+1;
16               pattern={};
17               length=0;
18               exist=-1;
19           }
20           else{
21               pattern[s[i]]=i;
22               i++;
23               length++;
24               if(length>longest_length){
25                   longest_length=length;
26               }  
27           }
28       }
29   }
30   return longest_length;
31 };

如果按照上面的方法,是可以通过的,但实际上有些开销是不必要的,像不断清空hashmap的操作能不能省略,也就有了再改进的方法,这个是参考discuss得出的,放上代码:

 1 var lengthOfLongestSubstring = function(s) {
 2     var pattern={};
 3     var i=0;
 4     var start=0;
 5     var max_length=0;
 6     while(i<s.length){
 7         if(s[i] in pattern && start<=pattern[s[i]]){
 8             start=pattern[s[i]]+1;
 9         }
10         else{
11             max_length=max_length>(i-start+1)?max_length:(i-start+1);
12         }
13         pattern[s[i]]=i;
14         i++;
15     }
16     return max_length;
17 };

实际上就是把字符串中的每一个元素都存在了hashmap中,如果之前在hashmap中存在当前元素,就直接跟新在hashmap中的下标的值,然后通过start来控制范围,也可以得到结果。

使用C++代码如下:

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         map<char,int> hashMap;
 5         int max_length=0;
 6         int start=0;
 7         for(int i=0;i<s.size();i++){
 8             map<char,int>::iterator it=hashMap.find(s[i]);
 9             if(it!=hashMap.end() && start<=hashMap[s[i]]){
10                 start=hashMap[s[i]]+1;
11             }
12             else{
13                 max_length=max(max_length,i-start+1);
14             }
15             hashMap[s[i]]=i;
16         }
17         return max_length;
18     }
19 };

 

Longest Substring Without Repeating Characters

标签:简单   去重   改变   判断   访问   char   turn   span   不重复   

原文地址:http://www.cnblogs.com/yuruilee/p/6367383.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!