二分法:假币寻找

假币寻找

      • 问题描述
      • 算法设计思路
      • 算法实现伪代码
      • 实现代码
      • 完整代码实现
      • 时间复杂度分析

问题描述

          有n枚外形相同的硬币,其中有一枚是假币,假币的重量比真币轻,但是目前仅有一台无砝码的天平。请设计一个算法,要求用最少的天平使用次数找出这枚假币。

算法设计思路

          当硬币数量k为偶数时,因为假币的重量比真币轻,所以可以对硬币分成2组,然后测试哪边比较轻,假币存在较轻的一方,再进行分组。当硬币数量为奇数时,可先忽略最后一个硬币,对k-1个硬币进行分组称量,若两边重量相等,则假币是最后一个,若两边不等,则将最后一个硬币和较重的一边删掉,此时剩下的硬币数为偶数,则可以进行上面的操作。

算法实现伪代码

功能:找出假币
输入:数组coins[] 1为真 0为假
输出:寻找假币使用的次数count
S1: if coins.length=2 or coins.length=3 count++ return
S2: half = coins.length/2
S3: if coins.length%2=0 //硬币数为偶数
S4: for i = 0 to half
S5: sum1 += coins[i]
S6: for i = half to coins.length
S7: sum2 += coins[i]
S8: else //硬币数为奇数
S9: for i = 0 to half
S10: sum1 += coins[i]
S11: for i = half-1 to coins.length
S12: sum2 += coins[i]
S13: if sum1 < sum2
S14: //再对半称量
S15: if sum1 > sum2
S16: //同理
S17: count++

实现代码

private static void solve(int[] coins) {//coins[]存放的是真假币如[1,1,1,0,1],1为真,0为假
		if(coins.length == 2 || coins.length == 3){//基值条件
			count++;
			return;
		}
		
		int half = coins.length/2;	//分成两部分进行比较
		int sum1 = 0;	//左半部分的重量
		int sum2 = 0;	//右半部分。。。
		
		if(coins.length%2 == 0) {//硬币数为偶数
			
			for(int i = 0;i < half;i++) {//左半部分的重量
				sum1 += coins[i];
			}
			for(int i = half;i < coins.length;i++) {//右半部分的重量
				sum2 += coins[i];
			}
			
		}else {					//硬币数为奇数
			
			for(int i = 0;i < half;i++) {
				sum1 += coins[i];
			}
			for(int i = half;i < coins.length-1;i++) {
				sum2 += coins[i];
			}
			
		}
		if(sum1 < sum2) {//当左边<右边,则可对左边进行再对半称量
			
			int[] newCoins = new int[half];
			for(int i = 0;i < half;i++) {
				newCoins[i] = coins[i];
			}
			solve(newCoins);
			
		}else if(sum1 > sum2){
			
			int[] newCoins = new int[half];
			int nElem = 0;
			for(int i = half;i < coins.length;i++) {
				newCoins[nElem++] = coins[i];
			}
			solve(newCoins);
		}
		count++;
	}

完整代码实现

public class Main {
	static int count = 0;
	public static void main(String[] args) {
		int[] coins = {1,1,1,1,1,1,0,1};
		solve(coins);
		System.out.println(count);
	}

	private static void solve(int[] coins) {
		if(coins.length == 2 || coins.length == 3){//基值条件
			count++;
			return;
		}
		
		int half = coins.length/2;	//分成两部分进行比较
		int sum1 = 0;	//左半部分的重量
		int sum2 = 0;	//右半部分。。。
		
		if(coins.length%2 == 0) {//硬币数为偶数
			
			for(int i = 0;i < half;i++) {//左半部分的重量
				sum1 += coins[i];
			}
			for(int i = half;i < coins.length;i++) {//右半部分的重量
				sum2 += coins[i];
			}
			
		}else {					//硬币数为奇数
			
			for(int i = 0;i < half;i++) {
				sum1 += coins[i];
			}
			for(int i = half;i < coins.length-1;i++) {
				sum2 += coins[i];
			}
			
		}
		if(sum1 < sum2) {//当左边<右边,则可对左边进行再对半称量
			
			int[] newCoins = new int[half];
			for(int i = 0;i < half;i++) {
				newCoins[i] = coins[i];
			}
			solve(newCoins);
			
		}else if(sum1 > sum2){
			
			int[] newCoins = new int[half];
			int nElem = 0;
			for(int i = half;i < coins.length;i++) {
				newCoins[nElem++] = coins[i];
			}
			solve(newCoins);
		}
		count++;
	}
}

时间复杂度分析

每次都会把硬币分为两半进行称量,即T(n) = 2T(n/2),
加上比较次数T(n)=2
T(n/2)+O(1)。
所以时间复杂度O(n)=logn

你可能感兴趣的:(算法设计)