巩固练习长度最小的子数组-904/76 【滑动窗口】

904.水果成篮

解题思路

简而言之,是为了找最长连续两个数的序列。
前面的理解了,自己上手又有点不行。自己写的↓,感觉思路是对的,却不行。(发现for循环初始化搞错了)

/**
* @param {number[]} fruits
* @return {number}
*/
var totalFruit = function(fruits) {
   let i = 0
   let flag = []
   let typeF = 0
   let maxLen = 0
   for(let j=fruits.length;j<fruits.length;j++){
       flag.push(fruits[j])
       if(!flag.includes(fruits[j])){ //如果篮子里没有这种水果则加入这种水果
           // flag.push(fruits[j])
           typeF++
       }
       if(typeF > 2){ //如果篮子里水果种类 > 2
           maxLen = Math.max(maxLen,j-i+1) //获取当前的序列长度
           //删除一种水果
           deletedF = flag.shift()//确定删除的这种水果
           i = flag.lastIndexOf(deleteF) != -1 ?  flag.lastIndexOf(deleteF) : i+1 //找到这种水果最后出现的位置,变更i的位置
           flag = flag.slice(i-1)//删除i之前的
           typeF--
       }
       
   }
   return flag.length
};

改正之后是

var totalFruit = function(fruits) {
   let i = 0
   let flag = []
   let typeF = 0
   let maxLen = 0
   for(let j=0;j<fruits.length;j++){
//        if(flag.lastIndexOf(fruits[j]) == -1){ //如果篮子里没有这种水果则加入这种水果
//        typeF++
//    } 这样也可以
       if(!flag.includes(fruits[j])){ //如果篮子里没有这种水果则加入这种水果
           typeF++
       }
        flag.push(fruits[j])
        // typeF = Array.from(new Set(flag)).length //获取现在的水果种类数
    //    console.log(typeF)
       if(typeF > 2){ //如果篮子里水果种类 > 2
           //删除一种水果
        //    deletedF = flag.shift()//确定删除的这种水果
        //    i = flag.lastIndexOf(deleteF) != -1 ?  flag.lastIndexOf(deleteF) : i+1 //找到这种水果最后出现的位置,变更i的位置
        //    flag = flag.slice(i-1)//删除i之前的
        //    typeF--
            flag.shift() //删除最前面的
            i++ //变更i的位置
            typeF = Array.from(new Set(flag)).length //获取现在的水果种类数
       }
       maxLen = Math.max(maxLen,j-i+1) //获取当前的序列长度
       
   }
   return flag.length
   //return maxLen 也可以
};

去看了别人的题解,是最大滑窗和最小话长的区别,感觉总结的很好:

  • 最小滑窗模板:给定数组 nums,定义滑窗的左右边界 i, j,求满足某个条件的滑窗的最小长度。
while j < len(nums):
    判断[i, j]是否满足条件
    while 满足条件:
        不断更新结果(注意在while内更新!)
        i += 1 (最大程度的压缩i,使得滑窗尽可能的小)
    j += 1

//作者:frostep
//链接:https://leetcode.cn/problems/fruit-into-baskets/solution/shen-du-jie-xi-zhe-dao-ti-he-by-linzeyin-6crr/
//来源:力扣(LeetCode)
//著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 最大滑窗模板:给定数组 nums,定义滑窗的左右边界 i, j,求满足某个条件的滑窗的最大长度。
while j < len(nums):
    判断[i, j]是否满足条件
    while 不满足条件:
        i += 1 (最保守的压缩i,一旦满足条件了就退出压缩i的过程,使得滑窗尽可能的大)
    不断更新结果(注意在while外更新!)
    j += 1

//作者:frostep
//链接:https://leetcode.cn/problems/fruit-into-baskets/solution/shen-du-jie-xi-zhe-dao-ti-he-by-linzeyin-6crr/
//来源:力扣(LeetCode)
//著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

JavaScript解法代码

var totalFruit = function(fruits) {
    let i = 0
    const blanket = new Map()
    let maxLen = 0
    for(let j=0;j<fruits.length;j++){
        blanket.set(fruits[j], (blanket.get(fruits[j]) || 0) + 1)
        while(blanket.size > 2){
            blanket.set(fruits[i], blanket.get(fruits[i]) - 1);
            if (blanket.get(fruits[i]) == 0) {
                blanket.delete(fruits[i]);
            }
            ++i;
        }
        maxLen = Math.max(maxLen, j-i+1)
    }
    return maxLen
};

Python解法代码

自己的

虽然可以AC,但其实是有问题的。

class Solution(object):
    def totalFruit(self, fruits):
        """
        :type fruits: List[int]
        :rtype: int
        """
        fruitsType = 0
        blanket = []
        for j in range(len(fruits)):
            if(fruits[j] not in blanket):
                fruitsType+=1
            blanket.append(fruits[j])

            if(fruitsType > 2):
                del(blanket[0])
                fruitsType = len(list(set(blanket)))
        return len(blanket)

滑动窗口

class Solution(object):
    def totalFruit(self, fruits):
        """
        :type fruits: List[int]
        :rtype: int
        """
        blanket = {}
        maxLen = 0
        i = 0
        for j in range(len(fruits)):
            count =( blanket.get(fruits[j]) or 0)+1
            blanket[fruits[j]] = count

            while(len(blanket) > 2):
                count = blanket.get(fruits[i])-1
                blanket[fruits[i]] = count
                
                if (blanket[fruits[i]] == 0):
                    del blanket[fruits[i]]
                i+=1
            maxLen = max(maxLen,j-i+1)
        return maxLen

76.最小覆盖子串

解题思路

用滑动窗口找最短的字符串。

出现的问题

没有对对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量这个限制条件作出处理,所以对于如"aa","aa"这中例子处理不了。

/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function(s, t) {
    let i = 0
    let substr = ''
    let allExist
    let minLen = Number.MAX_VALUE
    let minstr =''
    for(let j=0;j<s.length;j++){
        substr += s[j]
        
        //判断条件 substr是否包含了t内的每个字符
        allExist= [...t].every(char => substr.includes(char));
        while(allExist){
            temp = minLen
            minLen = Math.min(minLen,j-i+1)
            if(minLen < temp){ //字符串改变了,变短了,则存储此时的字符串
                minstr = substr
                console.log(minstr)
            }

            substr = substr.substr(1) //删除第一个字符
            allExist= [...t].every(char => substr.includes(char)); //判断allExist 是否仍满足条件
            i++            
            
        }
    }
    if(t.length < minstr.length){
        return ""
    }
    else{
        return minstr
    }
    
};

使用Map解决了上述的问题,但是提交的时候因为有个例子非常长,所以超出了时间限制。

/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function(s, t) {
    let tDict = new Map();
    [...t].forEach(element => {
        tDict.set(element, (tDict.get(element) || 0) + 1)
    })
    let i = 0;
    let substr = '';
    let substrDict = new Map();
    let allExist;
    let minLen = Number.MAX_VALUE;
    let minstr ='';
    for(let j=0;j<s.length;j++){
        substr += s[j]
        substrDict.set(s[j],(substrDict.get(s[j]) || 0)+1)
        //判断条件 substr是否包含了t内的每个字符
        // allExist= [...t].every(char =>  [...substrDict.keys()].join('').includes(char));
        allExist= [...t].every(char => substr.includes(char));

        [...t].forEach(element => {
            if(substrDict.get(element) < tDict.get(element)){ //如果少于,则allExist = false
                allExist = false
            }
        })
        
        while(allExist){
            temp = minLen
            minLen = Math.min(minLen,j-i+1)
            if(minLen < temp){ //字符串改变了,变短了,则存储此时的字符串
                // minstr = [...substrDict.keys()].join('')
                minstr = substr
                console.log('minstr:',minstr)
            }
            //删除第一个字符
            substr = substr.substr(1) 
            substrDict.set(s[i],substrDict.get(s[i])-1)
            if (substrDict.get(s[i]) == 0) {
                substrDict.delete(s[i]);
            }
            allExist= [...t].every(char => substr.includes(char));
            //"对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。"
            //判断t中字符的长度 与 substr比较
            [...t].forEach(element => {
                if(substrDict.get(element) < tDict.get(element)){ //如果少于,则allExist = false
                    allExist = false
                }
            }) 
            i++        
               
        }
    }
    return minstr
};

看了答案,还没参悟。
ta也是用Map,但是对map的size有更灵活的运用。

JavaScript解法代码


/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function (s, t) {
    const target = new Map();
    let minChar;
    let nowChar = "";
    [...t].forEach(element => {
    target.set(element, (target.get(element) || 0) + 1)
})
    let size = target.size
    let  i= 0
    for (let j=0; j < s.length; j++) {
        if (target.has(s[j])) target.set(s[j], target.get(s[j]) - 1);
        if (target.get(s[j]) === 0) size--
        // console.log('size: ',size, !size)

        while (!size) {
            nowChar = s.substring(i, j + 1);
            // console.log('nowChar: ',nowChar)
            if (target.has(s[i])) {
                target.set(s[i], target.get(s[i]) + 1)
                if (target.get(s[i]) === 1) {
                    size++
                    console.log(!minChar || minChar.length > nowChar.length)
                    if (!minChar || minChar.length > nowChar.length) minChar = nowChar; //!minChar 判断minChar不为空(不为初始值)
                    // console.log(minChar)
                 }
             }
             i++;
         }
     }
     return minChar ? minChar : '';
};

Python解法代码

//待完成

总结:

  1. map集合的操作要注意:包括set、get、has的运用
    target.set(element, (target.get(element) || 0) + 1)
  2. 滑动窗口通用解总结:
    • 最小滑窗模板:给定数组 nums,定义滑窗的左右边界 i, j,求满足某个条件的滑窗的最小长度。
while j < len(nums):
    判断[i, j]是否满足条件
    while 满足条件:
        不断更新结果(注意在while内更新!)
        i += 1 (最大程度的压缩i,使得滑窗尽可能的小)
    j += 1

//作者:frostep
//链接:https://leetcode.cn/problems/fruit-into-baskets/solution/shen-du-jie-xi-zhe-dao-ti-he-by-linzeyin-6crr/
//来源:力扣(LeetCode)
//著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 最大滑窗模板:给定数组 nums,定义滑窗的左右边界 i, j,求满足某个条件的滑窗的最大长度。
while j < len(nums):
    判断[i, j]是否满足条件
    while 不满足条件:
        i += 1 (最保守的压缩i,一旦满足条件了就退出压缩i的过程,使得滑窗尽可能的大)
    不断更新结果(注意在while外更新!)
    j += 1

//作者:frostep
//链接:https://leetcode.cn/problems/fruit-into-baskets/solution/shen-du-jie-xi-zhe-dao-ti-he-by-linzeyin-6crr/
//来源:力扣(LeetCode)
//著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值