力扣刷题-滑动窗口(LC 209、904、76 )

滑动窗口也可以看出双指针法:一快一慢指针搜索数组,快指针做窗口终止位置,慢指针做起始位置,一般是求在指针滑动时满足条件的窗口长度最值。

[209. 长度最小的子数组]

思路:快指针滑动中将每次所在位置加入现有总和,当总和到达或超过目标值,快指针停止滑动,慢指针滑动,将每次滑出的所在值减去;每当总和小于目标值时,快指针继续滑动。

代码:

var minSubArrayLen = function(target, nums) {
    var i=0; 
    var j=0;
    var current=0;
    var minLength=nums.length+1;//若子串存在,必定小于该值
    while(i<=nums.length){
        if(current>=target){
            if(j-i+1<minLength) minLength=j-i+1;
            current-=nums[i++];
        }
        else if(current<target){
            current+=nums[j];
        }
        if(j<nums.length-1 && current<target) j++;
        else if(j==nums.length-1 && current<target) break;
    }
    return minLength==nums.length+1?0:minLength;
};

[904. 水果成篮]

思路一:数组+滑动窗口

这是最开始没有想到hashMap时的笨方法。两个数组:bucketV:篮子,记录采摘水果种类;fruitNum:记录总共采摘的水果索引。

快指针遍历时三种情况:

1. 出现已经装入篮子中的同种水果:由于滑动窗口方法中,被替换掉的都是更早出现的水果,所以若快指针值已经存在篮子中且在篮子底部,需要从底部拿出重新放进顶部。

if(bucketV.includes(fruits[j])){ 
    fruitNum.unshift(fruits[j]); 
    if(bucketV.length==2 && bucketV[1]==fruits[j]){ 
        var temp=bucketV.pop(); 
        bucketV.unshift(temp); 
    } 
    j++; 
}


2. 篮子中水果种类还不超过两种,可以直接装入:

else if(bucketV.length<2){ 
    bucketV.unshift(fruits[j]); 
    fruitNum.unshift(fruits[j]); 
    j++; 
}


3. 有新水果但是篮中水果种类满了,拿出最久未出现的:

else{
    fruitNum.pop();
    if(!fruitNum.includes(fruits[i])) bucketV.pop();
    i++;
}

思路二:HashMap+滑动窗口。

利用map.set()在键相同的情况下会用新值覆盖旧值的特点,只需将快指针遍历的位置都map.set,就可以完成思路一中的先pop再unshift操作。当篮中水果总数超过时,找到map中最久未出现的索引值,即map中的最小值,删掉该键值对。将i移动至删去元素的后面一位。```

var totalFruit = function(fruits) {
    var bucketV=new Map();
    var maxNum=0;
    var i=0;
    for(var j=0;j<fruits.length;j++){
        bucketV.set(fruits[j],j);
        if(bucketV.size>2){
            var minIndex=j+1;
            for(let [fruit,index] of bucketV){
                if(index<minIndex) minIndex=index;
            }
            bucketV.delete(fruits[minIndex]);
            i=minIndex+1;
        }

        maxNum= Math.max(maxNum,j-i+1);
        
    }
    
    return maxNum;
    
};

[76. 最小覆盖子串]

思路:HashMap+滑动窗口。map记录t中出现的单个字符次数,若子串覆盖了n个,则减去n,以间接记录子串中包含的目标字符个数。type记录子串已满足个数的字符种类。这里要注意的就是type增减的条件。窗口终止位置一直滑动到type到达阈值,然后起始位置滑动,直到type小于阈值,终止位置继续滑动。循环条件也需注意。

代码

var minWindow = function(s, t) {
    var origin=s.split('');
    var target=t.split('');
    var map=new Map();
    var type=0;
    var result=[-1];
    result.push(origin.length);
    for(item of target){
        if(map.has(item)){
            var old=map.get(item);
            old++;
            map.set(item,old);

        }
        else map.set(item,1);
    }
    var originalLen=map.size;
    var start=0;
    var end=0;
    while(start<=origin.length){
        if(type==originalLen){
            if(end-start+1<result[1]-result[0]+1) {
                result[0]=start;
                result[1]=end;
            }
            if(target.includes(origin[start])){
                var old=map.get(origin[start]);
                if(old==0) type--;
                old++;
                map.set(origin[start],old);
                
            }
            start++;
        }
        
        else if(type<originalLen){
            if(map.has(origin[end])){
                var old=map.get(origin[end]);
                old--;
                if(old==0) {
                    type++;
                }
                map.set(origin[end],old);
            }
        }
        if(type<originalLen && end<origin.length-1) end++;
        else if(type<originalLen && end==origin.length-1) break;
    }
    if(result[0]==-1) return "";
    else return s.slice(result[0],result[1]+1);
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值