题目描述
小明从糖果盒中随意抓一把糖果,每次小明会取出一半的糖果分给同学们。
当糖果不能平均分配时,小明可以选择从糖果盒中(假设盒中糖果足够)取出一个糖果或放回一个糖果。
小明最少需要多少次(取出、放回和平均分配均记一次),能将手中糖果分至只剩一颗。
输入描述:
抓取的糖果数(<10000000000):15
输出描述:
最少分至一颗糖果的次数:5
示例 1
输入:15
输出:5
解释:
(1) 15+1=16;
(2) 16/2=8;
(3) 8/2=4
(4)4/2=2
(5)2/2=1
说明:因为测试用例有限,所以用解法1和解法2硬匹配前2000个结果,都是一样的,所以可以确认解法1是对的
#解题想法1:题目的要求是快速将糖分到1,所以1/2操作是最佳操作,能快速使糖数减少。
通过观察发现,有两个特点,一是,比如15,15+1是2^n,比15-1接下来再循环次数少,
从而推出,如果m+1或m-1是2^n,那么直接可以快速循环到1(一刀一半);二是,如果m+1是4的倍数,
那么可以三步快速刀到m+1的1/4,因为之前先判断了m-1、m或m+1不是2的次幂,m也不是偶数,
那么m是奇数,如果操作m-1,(m-1)/2如果不符合前面的判定条件那么又会是奇数,
有重复上述操作而增加步骤数,当然这里特例是m=3,那么减1再/2更快
def f2(m):
l = [2 ** i for i in range(1, int(m / 2))]
# print(l)
res = 0
while m != 1:
if m - 1 in l:
m = m - 1
res += 1
elif m + 1 in l:
m = m + 1
res += 1
elif m in l:
m = int(m / 2)
res += 1
else:
if m % 2 == 0:
m = int(m / 2)
res += 1
else:
if (m+1)%4==0:
if m>3:
m=m+1
res+=1
else:
m=m-1
res+=1
else:
m = m - 1
res += 1
# print(m, res)
return res
解题思想2:硬算
import collections
def f1(n):
queue = collections.deque()
queue.append(n)
def bfs(queue,target,depth):#depth即遍历几层后找到了1
while queue:
depth += 1
for i in range(len(queue)):
cur = queue.popleft()
if cur == target:
return depth
queue.append(cur+1)
queue.append(cur-1)
if cur%2 == 0:
queue.append(cur/2)
return bfs(queue,1,-1)
# print(bfs(queue,1,-1)) #之所以初始的depth为-1是因为第一次手中的糖果数量
如果就是目标数量,则需要的操作次数为0