904. 水果成篮「滑动窗口」「多指针?」

思路

第一时间想到的思路就是:找到一个这样的最长区间:区间内最多只有两个不同的数(如果数组中只有一个数的情况)

典型的滑动窗口问题。


多指针

沿用了昨天周赛T4的思路:6207. 统计定界子数组的数目
类似滑窗?

通过枚举右边界r,记录左边界下标l,额外利用几个变量来记录当前区间中存在哪两个数,并且记录其最后出现的下标位置:

  • x, y:区间中的两个数
  • lastX, lastYx, y最后出现的下标,用于更新区间左边界。

算法如下:

  1. 初始化x = y = lastX = lastY = -1, l = 0,ans = 0 ;
  2. 枚举右边界下标,每轮固定为r
    1. x == -1,说明第一个数还没有确定, 确定第一个数;若fruits[r] != x && y == -1,即可以确定第二个数。
    2. fruits[r] == x,更新lastX = r;若fruit[r] == y,更新lastY = r;否则进入下一步
    3. 此时有:fruits[r] != x && fruits[r] != y,说明遇到了第三个数,因此需要根据前面区间的信息对答案以及变量进行一次更新操作:
      1. 更新答案ans:由上面的步骤可知区间[l, r)内只存在两个数,ans = max(ans, r - l)
      2. 更新区间左边界ll = min(lastX, lastY) + 1;
      3. 更新第二个数x, lastXy, lastY:若lastX < lastY,则x = fruits[r], lastX = r;否则y = fruits[r], lastY = r

算法图示如下:

Solution904Image00.jpg

代码如下:

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int n = fruits.size();
        if(n <= 2){
            return n;
        }

        int x = -1, y = -1;
        int lastX=-1, lastY=-1;
        int l=0;  // 记录一个起点
        int ans = 0;

        for(int r=0; r<n; r++) {
            if(x == -1){
                x = fruits[r];
            }
            if(fruits[r] != x && y == -1){
                y = fruits[r];
            }

            if(x == fruits[r]){
                lastX = r;
            } else if(y == fruits[r]){
                lastY = r;
            } else {
                //遇到两个数之外的数了,更新答案;
                // ans = max(ans, max(lastX, lastY) - start + 1);
                ans = max(ans, r - l);

                //下一次的起点
                if(lastX < lastY){
                    l = lastX + 1;
                    x = fruits[r];
                    lastX = r;
                } else {
                    l = lastY + 1;
                    y = fruits[r];
                    lastY = r;
                }
            }

        }
        //区间遍历结束后,更新一次答案
        ans = max(ans, n - l);

        return ans;
    }
};

滑动窗口

实际上在前面一节中的方法与滑动窗口的思路是类似的。

滑动窗口的方法一样是枚举右边界right,记录左边界left

额外利用map来记录区间[left, right]中不同类型水果的数目。若map.size() > 2,说明此时区间中存在了三类水果,左边界left右移,同时对应的水果种类fruits[left]数量减1,直至有一个水果数目被减至0,将其从map中删除,此时得到了一个合法的区间, 更新ans即可。

代码如下:

class Solution {
public:
    //找到一个最长的连续区间:区间内只有两个数
    int totalFruit(vector<int>& fruits) {
        map<int, int> map;
        int n = fruits.size();
        int ans = 0;
        int left = 0;//初始左边界
        //枚举右边界
        for(int right = 0; right<n; right++){
            map[fruits[right]]++;
            while(map.size() > 2){
                if (--map[fruits[left]] == 0){
                    map.erase(fruits[left]);
                }
                left++;
            }
            ans = max(ans, right - left + 1);
        }
        
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值