编程之美-快速找出故障机器

package beautyOfCoding;

import java.util.Arrays;

public class TheLostID {

	/*编程之美 
	 假设一个机器仅存储一个标号为ID的记录,假设机器总量在10亿以下且ID是小于10亿的整数,假设每份数据保存两个备份,这样就有两个机器存储了同样的数据。
		1.假设在某个时间得到一个数据文件ID的列表,是否能快速地找出表中仅出现一次的ID?即快速找出出现故障的机器存储的数据ID。
        2.如果有两台机器出现故障呢?(假设存储同一份数据的两台机器不会同时出现故障,即列表中缺少的是两个不等的ID)
	 这里只考虑第2个问题:有两台机器出现故障,且缺少的是两个不等的ID
	 书上的解法4通过构造方程来解答,这有个前提是,需要知道所有的ID
	 我认为解法三(异或)更好
	 以下是解法三的实现
	 */
	public static void main(String[] args) {
		
		int[] c = {1,2,3,4,10,1,2,3,6,6};//ID列表
		TheLostID lostID = new TheLostID();
		lostID.process(c);
	}

	public void process(int[] c){
		if(c==null||c.length<4){//ID列表至少应该有4个ID
			return;
		}
		if(this.isValidInput(c)){
			this.find(c);
		}
	}
	
	/*
	 例如,对于数组{1,2,3,4,10,1,2,3},所有数字异或的结果是:
	 xor=4^10=(1110)-->最低位的1在倒数第二位(这个位置记为i位),表示4和10在i位是不相等的
	 那么,数组里面的数字可分为两组:一组是在i位上为1,另一组为0
	 让这两组数字各自内部异或,则能找到只出现一次的4和10
	 */
	public void find(int[] c){
		int len=c.length;
		int xor=0;
		for(int i=0;i<len;i++){
			xor ^=c[i];
		}
		int xor2=xor&(xor-1);//去掉xor二进制表示里面最低位的1
		int lastDiffBit=xor^xor2;//x,y在这一位是不相等的,一个为0,一个为1
		int x=0;
		int y=0;
		for(int i=0;i<len;i++){
			if((c[i]&lastDiffBit)==lastDiffBit){
				x ^=c[i];
			}else{
				y ^=c[i];
			}
		}
		System.out.println("x,y="+x+","+y);
	}
	
	/*
	判断数组是否符合以下条件:
	1、数组里面的数字,要么出现一次,要么出现两次
	2、出现一次的数字,有且只有两个
	最快的方法当然是用哈希表
	这里用的是 排序+遍历统计(如果数据量大,用排序也不如哈希表好)
	*/
	public boolean isValidInput(int[] c){
		Arrays.sort(c);//排序
		int len=c.length;
		int count=0;
		if(c[0]!=c[1]){
			count++;
		}
		if(c[len-1]!=c[len-2]){
			count++;
		}
		for(int i = 0;i<len;i++){
			if(i<=len-3){
				if(c[i]==c[i+1]&&c[i+1]==c[i+2]){//不能存在三个相等的数
					return false;
				}
			}
			//统计不相等的数有几个
			if(0<i&&i<len-1&&c[i]!=c[i-1]&&c[i]!=c[i+1]){
				count++;
			}
			if(count>2){
				return false;
			}
		}
		return count==2;
	}
}

你可能感兴趣的:(编程之美)