寻找假币
一、问题描述
一个袋子里有若干硬币,其中一枚是假币,并且和假币和真币一模一样,目前只知道假币比真币轻一点。请问如何找到这枚假币?
二、算法分析
根据分治的策略,将硬币平分为两份(奇数个硬币取出中间的硬币后再平分),比较两边的重量之和的大小。左侧重,则假币在右半段,反之,假币在左半段(或者中间的假币),然后继续在有假币的半区查找,直到剩余两个硬币,比较大小后,返回假币的位置。
时间复杂度:O(logn)。
三、代码实现
#include <stdio.h>
#define MAXNUM 30
int FalseCoin(int coin[], int low, int high)
{
// 两个硬币的比较
if (low + 1 == high) {
if (coin[low] < coin[high]) {
return low + 1;
}
return high + 1;
}
int sum1 = 0, sum2 = 0, sum3 = 0;
int mid = (low + high) >> 1;
int i;
// 偶数个硬币
if ((high - low + 1) % 2 == 0 ) {
// 左半段
for (i = low; i <= mid; i++) {
sum1 += coin[i];
}
// 右半段
for (i = mid + 1; i <= high; i++) {
sum2 += coin[i];
}
// 左侧重,则假币在右半段
if (sum1 > sum2) {
return FalseCoin(coin, mid + 1, high);;
}
// 右侧重,则假币在左半段
else if (sum2 > sum1){
return FalseCoin(coin, low, mid);;
}
else {
printf("没有假币。输入的硬币重量有误!");
}
}
// 奇数个硬币
else {
// 左半段,除去中间的一个硬币
for (i = low; i <= mid - 1; i++) {
sum1 += coin[i];
}
// 右半段,除去中间的一个硬币
for (int i = mid + 1; i <= high; i++) {
sum2 += coin[i];
}
sum3 = coin[mid];
// 左侧重,则假币在右半段
if (sum1 > sum2) {
return FalseCoin(coin, mid + 1, high);
}
// 右侧重,则假币在左半段
else if (sum2 > sum1){
return FalseCoin(coin, low, mid - 1);
}
else {
// 中间的是假币
if (coin[mid] != coin[low]) {
return mid + 1;
}
else {
printf("没有假币。输入的硬币重量有误!");
}
}
}
return -1;
}
int main()
{
int coin[] = { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 };
int position = FalseCoin(coin, 0, 9);
printf("假币在第 %d 个位置", position);
return 0;
}
假币在第 4 个位置