当前位置: 面试刷题>> 称重问题 (经典算法题500道)
### 题目描述补充
**称重问题**:
给定一组外观相同的硬币,但其中有一个是重量异常的(可能是更轻或更重),你只有一个天平,没有其他测量工具。问最少需要称重几次,才能确保找出这个异常的硬币,并且确定它是比正常硬币更轻还是更重?
假设总共有 N 个硬币,其中 N 是大于或等于 3 的奇数。
### 解题思路
对于 N 个硬币的问题,我们可以采用分治策略。将硬币分为三组,每组数量尽可能相等(对于奇数 N,其中两组数量相同,第三组多一个)。
1. 第一次称重:选择两组数量相同的硬币进行称重。
- 情况 A: 如果两边平衡,说明异常硬币在未称重的那组中。
- 情况 B: 如果不平衡,说明异常硬币在称重的两组中。
2. 第二次称重(对于情况 A):从未称重的那组硬币中继续分治。
- 将这组硬币再次分为三小组(尽量平均),选择两组进行称重。
- 重复上述逻辑,直到找到异常硬币。
3. 第二次称重(对于情况 B):从之前称重的两组中选择看起来较轻或较重的那组(取决于第一次称重的结果),并将这组硬币分为三小组(尽量平均),选择两组进行称重。
- 如果这两组仍然不平衡,说明异常硬币在其中,并且我们可以知道异常硬币是更轻还是更重。
- 如果这两组平衡,说明异常硬币在之前未称重的那组中,且异常硬币的重量与这次称重中使用的硬币相反(即如果这次称重是找轻的,那么异常硬币是重的,反之亦然)。
4. 重复步骤 2 和 3,直到找到异常硬币。
### 示例代码
由于篇幅限制,这里只给出 Python 的代码示例:
```python
def find_fake_coin(coins, lighter=True):
def weigh(group1, group2):
if sum(group1) < sum(group2):
return -1 # group1 轻
elif sum(group1) > sum(group2):
return 1 # group1 重
else:
return 0 # 平衡
def find_in_group(group, lighter):
n = len(group)
if n == 1:
return group[0], (lighter and -1 or 1) # 返回硬币及其是轻是重
third = n // 3
group1, group2, group3 = group[:third], group[third:2*third], group[2*third:]
result = weigh(group1, group2)
if result == 0:
return find_in_group(group3, not lighter)
else:
return find_in_group(group1 if result == (1 if lighter else -1) else group2, lighter)
return find_in_group(coins, lighter)
# 示例使用
coins = [1, 1, 1, 1, 2] # 假设第5个硬币更重
fake_coin, is_lighter = find_fake_coin(coins, lighter=False)
print(f"异常硬币索引: {coins.index(fake_coin)}, 是否更轻: {'否' if is_lighter == 1 else '是'}")
```
注意:这里的实现假设硬币的重量差异可以直接通过求和来体现,实际中可能需要使用更精确的天平测量。另外,索引是基于 0 的,并且代码中 `lighter` 参数用于指定是寻找更轻的硬币还是更重的硬币(这里设置为 `False` 表示寻找更重的)。
**码小课**网站中有更多关于算法和数据结构的内容分享,欢迎大家学习交流。