leetcode
leetcode 1351 ~ 1400
换水问题

换水问题

难度:

标签:

题目描述

超市正在促销,你可以用 numExchange 个空水瓶从超市兑换一瓶水。最开始,你一共购入了 numBottles 瓶水。

如果喝掉了水瓶中的水,那么水瓶就会变成空的。

给你两个整数 numBottlesnumExchange ,返回你 最多 可以喝到多少瓶水。

 

示例 1:

输入:numBottles = 9, numExchange = 3
输出:13
解释:你可以用 3 个空瓶兑换 1 瓶水。
所以最多能喝到 9 + 3 + 1 = 13 瓶水。

示例 2:

输入:numBottles = 15, numExchange = 4
输出:19
解释:你可以用 4 个空瓶兑换 1 瓶水。
所以最多能喝到 15 + 3 + 1 = 19 瓶水。

 

 

提示:

  • 1 <= numBottles <= 100
  • 2 <= numExchange <= 100

代码结果

运行时间: 18 ms, 内存: 16.1 MB


/*
题目思路:
1. 使用Java Stream实现,类似于普通方法。
2. 每次兑换时,使用stream计算出新水瓶数并累加。
3. 重复计算直到无法再兑换。
*/
import java.util.stream.Stream;

public class WaterBottlesStream {
    public int numWaterBottles(int numBottles, int numExchange) {
        return Stream.iterate(new int[]{numBottles, 0}, p -> p[0] >= numExchange, p -> new int[]{p[0] / numExchange + p[0] % numExchange, p[1] + p[0] / numExchange})
                .mapToInt(p -> p[1])
                .sum() + numBottles;
    }
}

解释

方法:

此题解采用了模拟的方法来计算可以喝到的水的总瓶数。初始情况下,总喝水瓶数等于开始购买的水瓶数。在每次迭代中,首先检查当前空瓶的数量是否足以进行至少一次兑换。如果可以,则根据兑换比率计算出新兑换得到的水瓶数,并将这些新瓶加入到总瓶数中。同时更新空瓶数,新的空瓶数是未兑换的空瓶加上新兑换的水瓶产生的空瓶。重复此过程,直到空瓶不足以兑换一瓶水为止。

时间复杂度:

O(log_{numExchange}(numBottles))

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中提到的迭代次数是基于什么假设?为什么说是numExchange的对数?
题解中的迭代次数基于每次兑换减少空瓶的数量的假设。每次兑换,你使用numExchange个空瓶换一瓶新水,因此每次兑换后剩余的空瓶数量减少。这个过程是对数的,因为每次兑换都是按比例减少空瓶数,空瓶数每次都减少到原来的numExchange分之一左右,所以整体迭代次数与numExchange的对数成正比。
🦆
如果numBottles小于numExchange,题解中的算法如何处理?还能正确返回结果吗?
如果numBottles小于numExchange,题解中的算法仍然能正确处理。在这种情况下,循环条件(empty_bottles >= numExchange)一开始就不成立,因此不会进入兑换循环,算法直接返回初始的numBottles作为结果。这意味着没有足够的空瓶来进行任何兑换,所以总喝水瓶数等于最初购买的瓶数。
🦆
题解中提到每次迭代空瓶数减少到原来的numExchange分之一,这个减少的逻辑是如何计算的?
实际上,题解的表述可能有所误导。每次迭代后,空瓶的数量不是简单地减少到原来的numExchange分之一,而是由两部分组成:未用于兑换的剩余空瓶(empty_bottles % numExchange)和新兑换的水瓶产生的空瓶(new_bottles)。这意味着空瓶数的减少是因为一部分空瓶被用来兑换新的水瓶,而每次兑换都会产生更少的新空瓶。
🦆
在题解中,为什么没有考虑使用递归方法解决这个问题?递归方法会有什么潜在的缺点?
在题解中没有采用递归方法,可能是因为递归方法在处理大数据量时可能会导致栈溢出,特别是在深度很大的递归调用中。递归方法虽然在理解和实现上可能更直接,但它需要额外的栈空间存储每一层递归调用的状态,而迭代方法通常更节省内存,执行效率也可能更高。因此,在处理可能需要大量迭代的问题时,迭代方法往往是更稳妥的选择。

相关问题