leetcode 3 :最长无重复子串

1.题目描述:求出一个字符串中最长的无重复字符的字符串长度

2.方法一:hash表+暴力解法

依次求出以每个字符打头的无重复的字符串的最大长度。通过hash表可以在o(1)时间内找到新加入的字符是否重复,不重复则加入hash表中,依次遍历后续字符,直到出现重复字符,则获得当前打头字符的最大不重复子串长度。判断是否需要更新maxlen。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int maxlen=0;
        for(int i=0;i<s.size();i++){
            unordered_map<char,int> map_ch;//必须放在循环内!!!!!
            int cnt=0,j=i;
            for(;j<s.size();j++){
                if(map_ch.find(s[j])!=map_ch.end()){
                    break;
                }
                map_ch[s[j]]=j;
            }  
            cnt=j-i;
            maxlen=cnt>maxlen?cnt:maxlen;//易错:不能将这行代码放进内层循环内,否则最后一次结果
                                         //无法更新,如,只有一个字符时,则立马出错
        }
        return maxlen; 
    }
};
  1. 优点:思路清晰简单;
  2. 缺点:时间复杂度为O(n^2)

3.方法二:hash表+加速暴力解法

方法一思路清晰简单,但是存在大量无用的重复计算,实际上可以通过以前的比较结果来加速后面的判断。实现o(n)的时间复杂度。准备两个下标i,j分别表示无重复子串的开头和结尾。

结论1:遍历后续字符过程中发现前面有重复字符。若前面的重复字符出现在i之前,则下一步搜索从i+1后开始i开头的子串必然不会是最长子串。(前面必然有比它长的),所以当前面重复字符出现在i之前时,更新下标后接着遍历后续字符

结论2:遍历后续字符过程中发现前面有重复字符。若前面重复字符出现在i或i之后,则下一步搜索从前面重复字符之后开始i开头的子串可能会是最长子串。之后记得还是要更新下标。

利用结论2可实现:加速1:可以排除从i到前面重复字符之间字符开头能够找到最长不重复子串的可能性,加速i

                               加速2:从k+1到j之间字符必然无重复字符,前面已经搜索过,不必重复计算,j++即可,加速j。

只要出现重复字符,无论在前在后,都要更新下标。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int maxlen=0,cnt=0,i=0,j=0,len=0;
        unordered_map<char,int> hash;
        len=s.size();
        while(i<len){//以每个字符打头
            while(j<len){//以i+1之后每个字符结尾
                if(hash.find(s[j])!=hash.end()&& hash[s[j]]>=i){
                    break;  
                }
                hash[s[j]]=j;//此时要更新下标
                j++; 
            }
            
            cnt=j-i;
            maxlen=max(maxlen,cnt);
            
            if(j<len){
                i=hash[s[j]]+1;//加速1
                hash[s[j]]=j;//更新重复字符,此处务必注意,要更新最新出现的重复字符,否则当出现
                             //重复字符时可能会误判断成i之前,那么就会出错
                j++;//加速2,不重复计算
            }else{
                break;
            }
        }
        return maxlen; 
    }
};

3.方法三:数组+加速暴力解法

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int maxlen=0,i=0,j=0,len=0;
        int exist[256];
        
       memset(exist, 0xff, sizeof(exist));//!!!!!切记易错
        
        len=s.size();
        while(i<len){//以每个字符打头
            while(j<len){//以i+1之后每个字符结尾
                if(exist[s[j]]!=-1 && exist[s[j]]>=i){
                    break;  
                }
               exist[s[j]] = j;
                j++; 
            }

            maxlen=max(maxlen,j-i);
            
            if(j<len){
                i = exist[s[j]] + 1;
                exist[s[j]] = j;            
                j++;
            }else{
                break;
            }
        }
        return maxlen; 
    }
};

类似的方法

class Solution {
public:
	int lengthOfLongestSubstring(string s) {
		int maxlen = 0, i = 0, j = 0, len = 0;
		int exist[256];

		memset(exist, 0xff, sizeof(exist));//!!!!!切记易错
		len = s.size();

		while (j<len){
			if (exist[s[j]] != -1){
				maxlen = maxlen>(j - i) ? maxlen:(j - i);
				while (i <= exist[s[j]]){
					exist[s[i]] = -1;
					i++;
				}
			}
            exist[s[j]] = j;
			j++;  
		}
        maxlen = maxlen>(j - i) ? maxlen:(j - i);//最后必须加此一句,如若只有一个字符a时,
                                                //无则出错
		return maxlen;
	}
};

4.方法四:动态规划

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值