LeetCode 003. Longest Substring Without Repeating Characters

Longest Substring Without Repeating Characters

 

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.


思路一:

本题最简单的思路就是将所有的子字符串都一一列举出来,然后判断每个字符串中是否包含重复字符,如果包含则舍弃,否则将该子字符串与maxlen进行比较,maxlen = max(maxlen, 当前子字符串的长度)。

算法复杂度分析:

一个长度为n的字符串,其子字符串的总数目为n*(n+1)/2。

然后每个字符串都要扫描一遍,当然如果出现重复字符则不用全部遍历一遍。因为每个位置上出现重复字符串的概率是一样的,因此这个过程复杂度为n/2。

所以总的复杂度为n*(n+1)*n/4,也就是O(n^3)

代码如下:

class Solution {
public:
    int lengthOfLongestSubstring(string s) 
    {
    	int i=0, j=0, k=0;
    	int len = s.length();
    	int maxlen = 0;
    	string tempstr = "";
    
    	for(i=0; i<len; i++)
    	{
    		for(j=i+1; j<=len; j++)
    		{
    			//获得从i到j的子字符串,一共有n*(n+1)/2个字符串
    			tempstr = s.substr(i,j-i);
    			//扫描子串中是否有单词重复
    			bool exist[256] = {false};
    			bool repeat = false;
    			for(k=0; k<tempstr.length()-1; k++)
    			{
    				//如果当前字符串中存在重复字符,则跳出循环
    				if(exist[tempstr[k]] == true)
    				{
    					repeat = true;
    					break;
    				}
    				exist[tempstr[k]] = true;				
    			}
    			if(!repeat)  //如果当前处理的字符串没有重复字符
    			{
    				if(tempstr.length()>maxlen)
    				{
    					maxlen = tempstr.length();
    				}
    			}			
    		}
    	}
    	return maxlen;
    }
};
这个代码我运行过,出现的结果并不是 Accepted,结果是 Time Limit Exceeded,下面给出的错误示例是一串非常长的字符串。

意思很明显,该算法不够快,复杂度太高了。

思路二

采用一个数组locs[256]记录已经访问字符的下标

(1)如果当前访问的字符没有出现过,记下当前字符出现的下标locs[s[i]] = i;,继续访问下一个字符
(2)如果当前访问的字符出现的过,且出现的位置大于当前处理子字符串起始位置locs[s[i]] > idx(idx是记录起始位置的前一个位置的下标),说明当前处理的子字符串已经是最大无重复字符的长度了,最大长度为i - idx,当前处理子字符串结束。然后i-idx与max作比较。
这种思路只需要遍历一遍字符串,复杂度为O(n)
代码如下:


class Solution {
public:
    int lengthOfLongestSubstring(string s) 
	{
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int max = 0;
        
        // 记录子串起始位置的前一个位置的下标
        // 初始化为-1
        int idx = -1;
        
        // 记录字符在s中出现的位置
		int locs[256] = {-1};

        for (int i = 0; i < s.size(); i++) 
		{
            // 如果s[i]在当前子串中出现过
            if (locs[s[i]] > idx) 
			{
                // 新子串的起始位置设为s[i]出现的位置+1
                // idx是记录起始位置的前一个位置的下标
                idx = locs[s[i]];
            }
            // 如果当前子串的长度大于最大值
            if (i - idx > max) 
			{
                max = i - idx;
            }
            // 更新字符s[i]出现的位置
            locs[s[i]] = i;
        }
        return max;
    }
};
参考链接: http://blog.csdn.net/pickless/article/details/9018575

思路三

采用一个bool类型数组exist[256] 来记录当前子字符串中已经访问过的元素,如果访问过则记为true,否则记为false。

用两个变量i,j记录当前处理子字符串的起始和终止下标。

逐个遍历字符串

(1)如果当前字符没在当前处理的子字符串中出现过,将当前字符标记为出现过exist[s[j]] = true;,然后继续访问下一个字符

(2)如果当前字符在当前处理的子字符串中出现过,则当前处理的子字符串结束,其长度为j-i,j-i与maxlen进行比较。下一个待处理的子字符串的起始下标必定是重复字符考前出现位置的下一个字符。这里不好讲清楚,我用下面的图片解释下。一开始处理的子字符串为ABEKSFORG,当访问到E的时候,出现了重复,则下一个处理的子字符串开始位置必定是K所在的位置,也即重复字符考前出现位置的下一个字符。与此同时,还需要将ABE三个字符的访问记录记为FALSE,因为下一个处理的子字符串起始字符是K,是没有包含ABE三个字符的。

这种思路也只需要遍历一遍字符串,复杂度也为O(n)


解释好费劲,上代码吧。

int lengthOfLongestSubstring(string s) 
{
  int n = s.length();
  int i = 0, j = 0;
  int maxLen = 0;
  bool exist[256] = { false };
  while (j < n) 
  {
	  if (exist[s[j]]) 
	  {
		  maxLen = max(maxLen, j-i);
		  while (s[i] != s[j]) 
		  {
			  exist[s[i]] = false;
			  i++;
		  }
		  i++;
		  j++;
	  } 
	  else 
	  {
		  exist[s[j]] = true;
		  j++;
	  }
  }
  maxLen = max(maxLen, n-i);
  return maxLen;
}

这个代码我只把该函数的代码贴出来了,如果需要直接嵌入到类里面就可以了。

参考链接:http://leetcode.com/2011/05/longest-substring-without-repeating-characters.html



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值