字符串的子串问题详解

原答案 https://leetcode.com/problems/minimum-window-substring/#/solutions


字符串的子串问题,大多可以用下面的模版解决

int findSubstring(string s){
        vector<int> map(128,0);
        int counter; // check whether the substring is valid
        int begin=0, end=0; //two pointers, one point to tail and one  head
        int d; //the length of substring

        for() { /* initialize the hash map here */ }

        while(end<s.size()){

            if(map[s[end++]]-- ?){  /* modify counter here */ }

            while(/* counter condition */){ 
                 
                 /* update d here if finding minimum*/

                //increase begin to make it invalid/valid again
                
                if(map[s[begin++]]++ ?){ /*modify counter here*/ }
            }  

            /* update d here if finding maximum*/
        }
        return d;
  }

这里我们可以分两种情况,一种是参数有两个字符串的,一种是参数只有一个字符串。两个字符串的题目一般要求我们在一个字符串中找另一个较短的字符串,可能是任意排列组合,也有可能是最小覆盖。参数只有一个字符串的题目一般要求我们在所给的字符串中找到符合某种要求的子串,比如只能有两个不同的字符,比如字符不重复。


1.参数为两个字符串的情况


例题:438. Find All Anagrams in a String

这道题跟我们之前的567题 很相似,不过这里我们改进做法,按模版的话复杂为O(n)。

首先套用模版,在初始化map时,把p中出现过的字符对应的位置加1。这里我们把count初始化为p.size,如果s中出现了在p中的字符,让count减一,如果count减到0,说明出现了p的一种排列。一般来说,参数是两个字符串的题,你要在长的字符串中找短的字符串,我们把count的值设为短字符串的长度。反之,在一个参数的题目中,我们把count初始化为0。

这道题本质上还是用到了slide window的思想,所以我们要保证,当窗口大小等于p的长度时,要让begin右移,同时维护map,让本来在begin减去的1加上。这里要注意,如果在begin的值在p中出现过,在淘汰这个值时,count也要+1,否则我们的计算没办法进行。详细版代码如下:

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
    	vector<int> indecies;
    	vector<int> map(128, 0);
    	for (int i = 0; i < p.size(); ++i)
    	{
    		map[p[i] - 'a']++;
    	}
    	int count = p.size(), begin = 0, end = 0;
    	while(end < s.size()){
    		if(map[s[end] - 'a'] > 0)count--;
    	    map[s[end] - 'a']--;	end++; 
    		if(count == 0)indecies.push_back(begin);
    		//keep the window size
    		//window size = end - begin ,end has been added 1
    		if(end - begin == p.size()){
    			//if s[begin] is is in p, count should ++
    			if(map[s[begin] - 'a'] >= 0)count++;
    			map[s[begin] - 'a']++; //reset the map because s[begin] is 
    			begin++; //move the window to right
    		}
    	}
    	return indecies;
    }
};

例题:76. Minimum Window Substring

这道题要求最小的窗口,使其含有子串中所有字符。我们增加一个minWin记录最小窗口长度,head记录最小窗口起点。其它的与上题类似。这道题题目中没有规定是小写字母,因为我们申明为128的数组,所以可以直接取字符做下标,不需要 -'a', 上一题其实也不需要。

class Solution {
public:
    string minWindow(string s, string t) {
        vector<int> hash(128, 0);
        for (int i = 0; i < t.size(); ++i)
        {
        	hash[t[i]]++;
        }
        int begin = 0, end = 0, count = t.size(), minWin = INT_MAX, head = 0;
        while(end < s.size()){
        	if(hash[s[end++]]-- > 0)count--;
        	while(count == 0){
        		if(end - begin < minWin){
        			minWin = end - begin;
        			head = begin;
				} 
				//判断begin处的元素在不在t中,hash[s[begin]] = 0说明在
			    //其实不会有>0的情况
        		if(hash[s[begin]] >= 0)count++;
        		hash[s[begin]]++; begin++;
        	}
        }
        return minWin == INT_MAX? "" : s.substr(head, minWin);
    }
};


 
1.参数为一个字符串的情况 

例题:3. Longest Substring Without Repeating Characters

一个字符串的题目,我们让count来表示出现的不满足条件的字符,如果count不等于0,那我们就需要调整begin的位置。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        vector<int> hash(128, 0);
        int begin = 0, end = 0, count = 0, maxLength = 0;
        while(end < s.size()){
        	if(hash[s[end]] != 0)count++;
        	hash[s[end]]++; end++;
        	while(count > 0){
        	    //如果出现过两次,这里的值就大于1,要还原
        		if(hash[s[begin]] > 1)count--;
        		hash[s[begin]]--; begin++;
        	}
        	maxLength = max(maxLength, end - begin);
        }
        return maxLength;
    }
    
};


//待更

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值