算法题目
小明喜欢从糖果盒里随意抓一把糖果。每次他抓到糖果后,会把手中一半的糖果分给同学们。要是手中的糖果数量不能平均分成两份,小明可以从糖果盒(假设盒中糖果数量足够多)里拿出一颗糖果,或者放回一颗糖果到盒子里。现在需要你计算,小明至少要进行多少次操作(取出或放回糖果、平均分配糖果都算一次操作),才能让手中的糖果只剩下一颗。
输入是小明抓取的糖果数,这个数字要小于 1000000。输出则是把手中糖果分至只剩一颗所需的最少操作次数。
例如,当输入为 15 时,小明的操作过程如下:
- 第 1 次,从糖果盒取出 1 颗糖果,手上糖果剩余:15 + 1 = 16。
- 第 2 次,平均分配,手上糖果剩余:16 / 2 = 8。
- 第 3 次,平均分配,手上糖果剩余:8 / 2 = 4。
- 第 4 次,平均分配,手上糖果剩余:4 / 2 = 2。
- 第 5 次,平均分配,手上糖果剩余:2 / 2 = 1。
所以输出是 5。
解题思路
我们可以采用递归的方法来解决这个问题。递归就是把一个大问题逐步分解成相同类型的小问题,直到问题简单到可以直接得出答案。
- 递归函数的设计:
- 我们要设计一个递归函数,这个函数的返回值是把当前剩余糖果分至只剩一颗所需的最少操作次数,函数的参数是当前剩余的糖果个数。
- 递归的终止条件是当糖果数量为 2 时,因为从 2 颗糖果分至 1 颗糖果只需要 1 次操作(平均分配),所以此时直接返回 1。
- 单层递归的逻辑:
- 如果当前糖果数是偶数,那么直接进行平均分配,操作次数加 1,然后继续递归处理剩下的一半糖果。
- 如果当前糖果数是奇数,就有两种选择:可以从糖果盒取出 1 颗糖果,也可以放回 1 颗糖果到盒子里。我们需要计算这两种情况下所需操作次数的最小值,然后加上本次操作的 1 次。
- 最后返回递归函数的最终结果。
示例代码
def divide_candies(candies_num):
if candies_num == 2:
# 当糖果数为 2 时,返回 1
return 1
if candies_num % 2 == 0:
# 当糖果数为偶数时,平均分配
return divide_candies(candies_num // 2) + 1
else:
# 当糖果数为奇数时,取出或放回的次数最小值
return min(divide_candies(candies_num + 1) + 1, divide_candies(candies_num - 1) + 1)
def solve_method(n):
if n > 1000000:
return False
return divide_candies(n)
if __name__ == '__main__':
assert solve_method(15) == 5