leetcode 904. Fruit Into Baskets(水果放进篮子)

两种方法解决水果装篮问题
文章介绍了如何使用动态规划(DP)和双指针法解决一个编程问题:给定一个数组表示水果类型,只有两个篮子,每个篮子只能装一种类型的水果,求最多能装多少个水果。通过维护两个篮子的状态和前一个数字的计数,分别实现DP和双指针解决方案,并给出了相应的Java代码实现。

在这里插入图片描述

水果放进篮子的问题,

fruits数组里面的数字是每个水果的类型,当前位置对应一个水果。

只有2个篮子,每个篮子只能放一种水果,不能几种水果混放,不限制每个篮子放的水果个数。

从左到右遍历数组,可以选择一个开始的index, 从这个index开始,每经历一个数字,都要把该数字类型的水果放进篮子里,那水果不是不能几种类型混着放么,要是和篮子里面的水果类型不匹配怎么办,那就到此为止,结束。

统计两个篮子里最多能放多少个水果。

思路:

方法1: DP

因为只有2个篮子,降低了复杂度,两个篮子就对应前面出现的2种类型(2个数字)。
因为只有2个数字,当无法再继续放的时候(当前数字和前面2个数字不匹配),更新之前放的水果的最大值,然后从头开始(保留前面的一个数字和当前数字,前面第1个数字抛弃)。

这样说可能一头雾水,举个例子吧,
pr1, pr2表示保存的当前两个篮子里面放的类型。
dp表示到当前index时2个篮子里的水果数。
prCnt表示当前index-1处的数字连续出现的个数。这是为了统计当index处的水果和2个篮子里的水果不匹配时,需要从index-1处重新开始放,而index-1处的数字已经连续出现了多少次(前面一种类型的水果已经放了多少个)。

fruits: 3  3  3  1  2  1  1  2  3  3  4
dp:     1  2  3  4  2  3  4  5  2  3  3
pr1:    3  3  3  3  1  2  2  1  2  2  3
pr2:   -1 -1 -1  1  2  1  1  2  3  3  4
prCnt:  1  2  3  1  1  1  2  1  1  2  1
res:    1  2  3  4  4  4  4  5  5  5  5

所以,看明白了吗。刚开始的时候只有pr1=fruits[0], pr2=-1,
dp[0] = 1, 因为这时候只有一个水果,
到第2个的时候,还是3,跟pr1一样,所以pr2还是-1,
prCnt是它前面一个数字3出现的次数,只出现了一次,所以是1,
因为3和pr1相同,所以dp[1] = dp[0] + 1,

第3个3和上面一样,来看看第4个数字1,
它既不等于pr1, 也不等于pr2, 而现在只有pr1有值,pr2还是-1,所以更新pr2=1,
现在它和pr1或pr2相等了,所以dp[3] = dp[2] + 1 = 4,
这是和pr1或pr2相等的情况。

那么再看和pr1和pr2都不相等的情况,第5个数字2,
因为它和前两个篮子的水果都不匹配,所以要放弃类型为3的水果,
取它的前一个类型2,从2开始,
那么2已经连续出现了几次呢,就是prCnt=1
这是dp[4] = prCnt + 1 = 2.

第6个数字1来的时候,它和pr1相等,dp[5] = dp[4] + 1,
但是我们要保证pr1和pr2的顺序(不然可能新出现的数字被放弃了),1现在是最新出现的,应该保存在pr2,
所以把pr1和pr2交换一下顺序。

    public int totalFruit(int[] fruits) {
        int n = fruits.length;
        int res = 1;
        int pr1 = fruits[0], pr2 = -1;
        int[] dp = new int[n];
        int prCnt = 1;

        dp[0] = 1;
        if(n > 1) {
            dp[1] = 2; 
            res = 2; 
            if(fruits[1] != pr1) {
                pr2 = fruits[1];
            } else {
                prCnt = 2;
            }
        }

        for(int i = 2; i < n; i++) {
            if(pr2 == -1 && fruits[i] != pr1) {
                pr2 = fruits[i];
            }
           
            if(fruits[i] == pr1 || fruits[i] == pr2) {
                if(fruits[i] == pr1) {
                    int tmp = pr1;
                    pr1 = pr2;
                    pr2 = tmp;
                }
                if(fruits[i] == fruits[i-1]) prCnt ++;
                else prCnt = 1;
                dp[i] = dp[i-1] + 1;             
            } else {
                dp[i] = prCnt + 1;
                prCnt = 1;
                pr1 = pr2;
                pr2 = fruits[i];
            }

           
            res = Math.max(res, dp[i]);
        }
       
        return res;
    }

方法2: 双指针

上面的DP方法需要统计前一个数字出现的次数prCnt,也可以用双指针记录前一个数字出现的起点和终点,用终点减去起点就是前一个数字出现的次数。
其他的都差不多。

    public int totalFruit(int[] fruits) {
        if (fruits.length == 1) {
            return 1;
        }
        int left = 0;
        int res = 0;
        int[] currFr = new int[]{fruits[0], -1};
        for (int right = 1; right < fruits.length; ++right) {
            int fr = fruits[right];
            if (fr != currFr[0] && fr != currFr[1]) {
                if (currFr[1] == -1) {
                    currFr[1] = fr;
                    continue;
                }
                //统计前一个数字出现的次数
                res = Math.max(res, right - left);
                //更新新的前一个数字起点和终点指针
                int prevFr = fruits[right - 1];
                left = right - 1;
                while (fruits[left - 1] == prevFr) {
                    left--;
                }
                //更新最新的2个数字
                currFr[0] = prevFr;
                currFr[1] = fr;
            }
        }
        return Math.max(fruits.length - left, res);
    }
### 回答1: 2020美国数学建模竞赛C题是关于船舶重载的问题。该问题要求我们确定什么样的载重量将导致船只的深度过浅,进而导致拖底的风险。这个问题的复杂性在于,船只在运行过程中,其深度会随着载重量而改变,因此我们需要建立一个模型来描述这个过程。 为了解决这个问题,我们可以从以下几个方面入手: 1. 建立数学模型:我们可以通过建立一个差分方程组来描述船只载重量与其深度的关系,并利用数值方法进行求解。 2. 数据预处理:我们需要对数据进行预处理,通过对数据进行清洗、归一化和特征选择等操作,提取出与问题相关的因素进行分析。 3. 团队合作:团队成员间需要协作,分工合作,互相协调,才能较好地解决问题。 4. 结果分析:通过对模型结果进行分析,确定哪些载重量将导致船只的深度过浅,因此需要采取相应的措施,避免拖底风险。 综上所述,2020美国数学建模竞赛C题是一道较为复杂的问题,需要团队成员之间的高度配合和优秀的数学建模技能。可以通过逐步分析和细致的工作流程来解决这个问题。 ### 回答2: 2020美赛C题是一道关于高峰时段公共交通的问题。此题的主要目标是优化传统的公共交通服务,以适应庞大的工作人口在高峰时段的需求,同时保持交通流量的稳定性和可行性。 在此题中,我们需要综合考虑如何在给定的路线网络上配置公交车辆、确定站点位置、调度行车、管理乘客等问题。这个问题可以分成四个方面来分析: 首先,我们考虑如何确定站点。我们需要分类考虑不同地点的出行量,然后提取出来加入站点网络。其中,我们可以利用聚类算法和可行性算法来确定站点位置。 对于较为密集的区域,我们需要根据聚集程度放置多个站点;对于出行量较低的地区,我们可以简化站点网络,以节省成本。 其次,我们考虑如何配置车辆。在给定的路线网络中,我们需要选择最优路线,以将车辆需要的时间缩短到最小。选择均衡的路线还可以缓解拥挤现象。可以通过遗传算法等优化方法实现车辆的最优配置。 第三,我们需要描述如何管理乘客。在高峰期内,人流量较大,需要有效利用公共交通系统以缓解人口拥堵,坚持手动调度选定道路运输模式,并对乘客进行治理。我们需要通过社交力量将乘客引导至正确的入口和出口,以使人流更加平衡。同时,我们需要建立合理的乘客数量控制机制,以防止超载、过度拥挤等问题最后,我们考虑如何评估策略的有效性。评估公共交通服务的质量通常是使用客流量和时间延迟这两个指标。我们可以使用相关的统计和机器学习方法来预测和评估公共交通服务的质量,从而更好地改善系统服务质量。 综上所述,本题需要综合考虑各种因素,如工作人口、路线网络、车辆配置、乘客管理和策略评估等等,最终得出一个高峰时段公共交通的优化方案。 ### 回答3: 2020美赛C题是一道关于最优化和建模的题目。该题涉及到拓扑结构的优化,即如何使得一个网络连接的节点之间的传输距离最短,从而降低传输时间和成本。 建模过程中,首先需要根据题目中的数据生成网络的拓扑结构图,并将节点之间的距离作为变量。然后,需要使用数学和优化理论来构建目标函数,并确定约束条件。其中,目标函数是为了最小化网络中节点之间的相对距离,以实现传输路线更短的目的。而约束条件则包括了每个节点至少需要连接一条边、所有边的总数量以及节点之间不能出现环等限制条件。 接下来,需要选择合适的算法进行求解。常见的算法有贪心算法、动态规划算法、启发式搜索算法等。对于本题来说,需要考虑采用带有约束的非线性规划算法来求解最优解。 最后,需要对求解结果进行分析和解释,提取有价值的信息和结论。可以从网络拓扑结构的角度出发,分析网络的稳定性、可靠性以及传输效率等方面的因素,从而帮助用户优化网络设计和管理。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值