java解决水果成篮(题904):数组+滑动窗口

48 篇文章 0 订阅
8 篇文章 0 订阅

一、问题描述

水果成篮
说明:题目来自leetcode

CategoryDifficultyLikesDislikes
algorithmsMedium (44.44%)165-
Tags Companies

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

  • 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
  • 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
  • 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。

给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

示例 1:

输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。

示例 2:

输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。

示例 3:

输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。

示例 4:

输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。

提示:

  • 1 <= fruits.length <= 105
  • 0 <= fruits[i] < fruits.length

二、思路

该题为滑动窗口问题,涉及多指针,特色可能是通过数组来保存篮子采摘水果种类。

简介 :

  • 先使用两个变量作为两个篮子,主要是记录果树种类;

  • 先使用right指针遍历数组,如果此时两个篮子都已经装有水果,并且该right指针对应的水果的种类不属于篮子中水果的种类,于是:

    • 1、计算已经采集的果树的棵树,并使用变量count记录;

    • 2、对左指针(left)重置;

    • 3、对篮子所对应的种类重置;

前提引入:

  • 计划是使用区间为[left,right-1]来记录两种果树的最长范围,于是后面就用((right-1)- left + 1) = (right - left)来记录此时子数组的长度;

  • 使用左指针left来表示子果树数组的左端点;

  • 设置整型数组kind(大小为2)来表示篮子的种类情况,初始值均为-1,代表还没有确认水果的种类;当确认了水果种类对数组的数值修改为水果种类;

xin麒的思路分析(具体实现):

先定义数组kind来记录水果篮要装的水果的种类、int变量count是记录子数组的长度、int型变量1left作为水果子数组左指针、int型变量note作为判断子数组是否等于整个数组(后面会说);

  • 1.1、首先kind没有一个元素初始值为-1,在循环里面当遇到第一个元素时先判断第一个篮子是否为-1:如果是-1,表示还没有确认,于是将该**fruit[right]赋值给kind[0]**表示确认了一种水果类型,于是继续果农探索下一棵果树;
  • 1.2、继续循环时,如果再次遇到和**kind[0]**类型相同的水果时,那么可以采摘,于是继续果农探索下一棵果树;

  • 1.3、继续循环时,如果**fruit[right]kind[0]不相等,并且kind[1]**等于-1,说明遇到新的水果种类,同时第二个篮子还没有确认水果的种类,那么就让第二个篮子确定种类kind[1] = fruit[right],于是继续果农探索下一棵果树;

  • 1.4、继续循环时如果遇到和篮子**kind[1]**确认的水果种类,那么说明可以采摘,于是继续果农探索下一棵果树;
  • 2.1、当遇到第三种水果时(此时fruit[right]不属于两个篮子的认定的水果种类 ),那么就需要记录一下之前两种水果树的采摘数量了,结果为((right-1)- left + 1) = (right - left);先是和count比较,如果count小,才可以将(right - left)赋值给count;
  • 2.2、于是对left进行处理,为了实现将当前水果的子数组的水果种类处理为1种,而且另一种新的水果种类为**fruit[right],于是我们需要:将fruit[right - 1]作为第一个水果篮子的确定的水果类型、将fruit[right]**作为第二个水果篮子的确定的水果类型;注意:这里的选取尤为重要,决定了left是从子数组的右端还是左端开始遍历
  • 2.3、上述为了实现上述需要,我们取一个变量start = right-2 作为指针,从fruit[start]向左遍历,当fruits[right - 1] == fruits[start]不成立时,便停下,说明fruit[left]为之前kind[0]类型的水果树,于是退出循环;于是left = start + 1;同时将**fruit[right-1]赋值于kind[0]篮子,将fruit[right]赋值于kind[1]**篮子;
  • 3.1、考虑到如果没有进入循环,那么note的数字始终不变(初始值设置为**-2**,也可以设置为其他,反正都是为了标记),那么说明该果园仅仅2种水果,并且count就没有被改变(也就是依然为初始值0);于是我们可以判断note是否为**-2**,如果是直接返回所有果树组成的长度;
  • 3.2、还有一种情况没有被统计,就是最后一次循环得到的子数组,循环退出时,索引在区间**[fruit.length - 1,left]的果树没有条件,于是将((fruits.length - 1) - left + 1)**与count比较一下,返回其中大的值;

三、xin麒的题解:

class Solution {
    public int totalFruit(int[] fruits) {
        int[] kind = {-1,-1};
        int count = 0;
        int left = 0;
        int note = -2;
        for (int right = 0; right < fruits.length; right++) {
            if (kind[0] == -1){
                kind[0] = fruits[right];
                continue;
            }
            if (kind[0] == fruits[right]){
                continue;
            }
            if (kind[1] == -1){ 
                kind[1] = fruits[right];
                continue;
            }
            if (kind[1] == fruits[right]){
                continue;
            }
            note = 0;
            int number = right - left;
            if (number > count){
                count = number;
            }
            int start = right - 2;
            while (fruits[right - 1] == fruits[start]){
                start--;
            }
            left = start + 1;
            kind[0] = fruits[right -1];
            kind[1] = fruits[right];
        }
        
        if(note == -2){
            return fruits.length;
        }
        if(fruits.length - left> count){return (fruits.length - left);}
        return count;
    }
}
运行:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZCrcMeKA-1646393518288)(C:\Users\86189\AppData\Roaming\Typora\typora-user-images\image-20220301225219138.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值