换水问题

标签: 数学 模拟

难度: Easy

超市正在促销,你可以用 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

Submission

运行时间: 18 ms

内存: 16.1 MB

class Solution:
    def numWaterBottles(self, numBottles: int, numExchange: int) -> int:
        total_bottles = numBottles  # 已经喝过的瓶子数(包括兑换的)
        empty_bottles = numBottles  # 当前的空瓶子数
        
        while empty_bottles >= numExchange:
            new_bottles = empty_bottles // numExchange  # 可以兑换的新瓶子数
            total_bottles += new_bottles  # 更新已经喝过的瓶子数
            empty_bottles = empty_bottles % numExchange + new_bottles  # 更新剩余的空瓶子数
        
        return total_bottles

Explain

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

时间复杂度: O(log_{numExchange}(numBottles))

空间复杂度: O(1)

class Solution:
    def numWaterBottles(self, numBottles: int, numExchange: int) -> int:
        total_bottles = numBottles  # 初始化总喝水瓶数为开始的瓶数
        empty_bottles = numBottles  # 初始化空瓶数也为开始的瓶数
        
        while empty_bottles >= numExchange:  # 当空瓶数足够兑换时继续
            new_bottles = empty_bottles // numExchange  # 计算可以兑换的新瓶数
            total_bottles += new_bottles  # 更新总喝水瓶数
            empty_bottles = empty_bottles % numExchange + new_bottles  # 更新空瓶数
        
        return total_bottles  # 返回最终的总喝水瓶数

Explore

题解中的迭代次数基于每次兑换减少空瓶的数量的假设。每次兑换,你使用numExchange个空瓶换一瓶新水,因此每次兑换后剩余的空瓶数量减少。这个过程是对数的,因为每次兑换都是按比例减少空瓶数,空瓶数每次都减少到原来的numExchange分之一左右,所以整体迭代次数与numExchange的对数成正比。

如果numBottles小于numExchange,题解中的算法仍然能正确处理。在这种情况下,循环条件(empty_bottles >= numExchange)一开始就不成立,因此不会进入兑换循环,算法直接返回初始的numBottles作为结果。这意味着没有足够的空瓶来进行任何兑换,所以总喝水瓶数等于最初购买的瓶数。

实际上,题解的表述可能有所误导。每次迭代后,空瓶的数量不是简单地减少到原来的numExchange分之一,而是由两部分组成:未用于兑换的剩余空瓶(empty_bottles % numExchange)和新兑换的水瓶产生的空瓶(new_bottles)。这意味着空瓶数的减少是因为一部分空瓶被用来兑换新的水瓶,而每次兑换都会产生更少的新空瓶。

在题解中没有采用递归方法,可能是因为递归方法在处理大数据量时可能会导致栈溢出,特别是在深度很大的递归调用中。递归方法虽然在理解和实现上可能更直接,但它需要额外的栈空间存储每一层递归调用的状态,而迭代方法通常更节省内存,执行效率也可能更高。因此,在处理可能需要大量迭代的问题时,迭代方法往往是更稳妥的选择。