1. 可怜的小猪

有1000只水桶,其中有且只有一桶装的含有毒药,其余装的都是水。它们从外观看起来都一样。如果小猪喝了毒药,它会在15分钟内死去。
问题来了,如果需要你在一小时内,弄清楚哪只水桶含有毒药,你最少需要多少只猪?
回答这个问题,并为下列的进阶问题编写一个通用算法。
进阶:
假设有 n 只水桶,猪饮水中毒后会在 m 分钟内死亡,你需要多少猪(x)就能在 p 分钟内找出“有毒”水桶?n只水桶里有且仅有一只有毒的桶。

分析:

需要在一小时内测试出哪桶水有毒,而每头猪喝下毒药会在15分钟内死去,因此猪就有了五个时间状态,0min,15min,30min,45min,60min.
当测试用例buckets是1时,这桶水就是有毒的水,因此就是需要0头猪;
1头猪1个小时内可以测5桶水,每个状态下喝下一桶,若在某个时间点死去,则就是这桶水有毒。
先看一下2头猪可以测多少桶水呢?将每桶水按二维来编号,由于猪有5个状态,每行每列放5桶水 :

可怜的小猪、最小移动次数使数组元素相等-LeetCode题库
上述的两个箭头分别代表两个猪测试水的方向。
猪1和猪2在0min分别喝第0行和第0列的水,如果两头猪都没事,接着按行按列往下喝,如果某个时间点猪1或猪2死去了,说明猪1或猪2喝的某行某列有水有毒
猪1死去,猪2没死,猪1测出了哪行水有毒, 猪2需要在剩下的时间在每个时间点喝下此行剩下的水  ,直到死去,测出哪桶水有毒。猪2死去,猪1没死同理。
若猪1和猪2同时死去,那就是他们喝的行列交叉处的水有毒。
分析完2头猪可以测25桶水,我们可以得知每个猪可以占一个维度来测试水,即3头猪可以测5^3=125桶水,4头猪可以测5^4=625桶水,5头猪可以测5^5=3125>1000桶水,因此需要5头猪就可以测出来。
进阶:
先算出有几个时间状态: minutesCount = p/m +1;
x头猪各占一个维度:   当    minutesCount^x<n && minutesCount^x>=n时,x就是我们需要的小猪数.

代码:

public class Test_0131 {
	public static void main(String[] args) {
		Solution So = new Solution();
		int buckets = 1000;
		int minutesToDie = 15;
		int minutesToTest = 60;
		System.out.println(So.poorPigs(buckets, minutesToDie, minutesToTest));
	}
}
class Solution {
    public int poorPigs(int buckets, int minutesToDie, int minutesToTest) {
        int minutesCount = minutesToTest/minutesToDie +1;
        int poorPigs = 0;
        int maxBuckets = 1;
        while(maxBuckets < buckets){
        	poorPigs++;
        	maxBuckets *= minutesCount;
        }
        return poorPigs;
    }
}

2. 最小移动次数使数组元素相等
给定一个长度为 n 的非空整数数组,找到让数组所有元素相等的最小移动次数。每次移动可以使 n - 1 个元素增加 1。
示例:
输入:
[1,2,3]
输出:
3
解释:
只需要3次移动(注意每次移动会增加两个元素的值):
[1,2,3]  =>  [2,3,3]  =>  [3,4,3]  =>  [4,4,4]

分析:
正向思考:计算数组最大元素与最小元素的差,给小于最大元素的数组元素都加上这个数,判断数组的元素是否已全部相等,如果不相等,接着执行上述操作,直到全部相等,为了得到最大元素和最小元素,可以使用数组排序。
逆向思考:每次移动让除去最大元素的剩余n-1个数加1,相当于每次移动让选定的数减1,所以最少移动次数其实就是所有元素减去最小元素的和。

代码:

class Solution {
    public int minMoves1(int[] nums) {
    	int count = 0;
    	while(compare(nums) == false){
    		Arrays.sort(nums);//数组排序
    		int n =nums[nums.length-1]-nums[0];
    		for(int i = 0; i<nums.length-1; i++){
    			nums[i] += n;
    		}
            count += n;
    	}
    	return count;
    }
    private boolean compare(int[] nums) {
    	int c = nums[0];
    	for(int i=1; i<nums.length; i++){
    		if(nums[i] !=c){
    			return false;
    		}
    	}
    	return true;
    }
    public int minMoves2(int[] nums) {
    	int sum = nums[0];
    	int min = nums[0];
    	for(int i=1; i<nums.length; i++){
    		sum += nums[i];
    		if(nums[i] <min)
    			min = nums[i];
    	}
    	return sum -nums.length*min; 
    }
}

 

相关文章: