双索引技术

双索引技术(Two Pointer)

滑动窗口:这两个索引表示的是一个窗口,让这个窗口不停的在数组中滑动,来找到问题的解。

-什么叫子数组:可以不连续。但是本题强调了是要连续的。、

解法一:滑动窗口

时间复杂度:O(n),空间复杂度O(1) 因为没有另外开辟空间。

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        //初始化,希望区间不包含任何元素
        int l = 0, r = -1;   //nums[l...r]为我们的滑动窗口
        int sum = 0;    //
        int res = nums.size()+1;    //连续子数组初始化为数组的长度+1
        
        while(l<nums.size()){
            if(r+1<nums.size() && sum<s){
                r++;
                sum += nums[r];     //应注意r的取值不能越界
            }
            else{
                sum -= nums[l];
                l++;
            }
            if(sum >= s)
                res = min(res, r-l+1);
        }
        
        if(res == nums.size()+1)
            return 0;
        
        return res;
    }
};

思路:和209类似采用滑动窗口的思路。在[l...r]区间中表示不重复的字符集,为了扩大当前的字符集,加载一位新的元素时要判断新元素是否在[l...r]中,若不在扩大r+1,若在就将左边界l减至重复元素之后。在此期间不断更新维护字符区间的长度。

如何判断新的元素是否在字符集区间呢?遍历查找?find?这里有个小技巧,查表
预定义一个256大小的数组来维护字符集区间内元素出现的频率freq[256]初始为0,当加入1个元素对应的元素下标+1,当从字符集中删除一个元素对应删除元素下标需要-1,最终通过查表来看该元素是否在字符集空间。  这个想法很巧妙啊 :)

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int freq[256] = {0};   //记录数组中的字符出现的频率
        int l=0, r = -1;      //滑动窗口为s[l...r]
        int res = 0;         //满足条件的字串的最长长度
        
        while(l<s.size()){
            if(r+1<s.size() && freq[s[r+1]]==0){
                //r+1为下标的字符出现的频率为0时,可以向右扩张
                r++;
                freq[s[r]]++;
            }
            else{
                //重复出现时,左侧窗口向右移,即缩小
                freq[s[l]]--;
                l++;
            }
            res = max(res, r-l+1);
        }
        return res;
    }
};

 

猜你喜欢

转载自www.cnblogs.com/Bella2017/p/10159234.html