《编程之美》读书笔记-1.5快速找出机器故障

题目:假设一个机器只存储一个标号为ID的记录,假设每份数据保存2个备份,这样就有2个机器存储了相同的数据。其中ID是小于10亿的整数

问题1、在某个时间,如果得到一个数据文件ID的列表。是否能够快速的找到这个表中仅出现一次的ID?即快速找出出现故障的机器存储的数据ID。

问题2、如果有两台机器死机呢?(假设同一个数据的俩个备份不会同时丢失,即列表中缺少的是两个不等的ID)

———————————————————————————————————————

一份数据拥有一个独一无二的ID,备份数据的ID与原始数据的ID相同,备份数据与原始数据存储在不同的机器上。文件列表中的ID包含了两个机器的信息,所以如果某个机器坏掉,文件列表当中这存在一个关于数据的ID


对于问题1,最直观的方法就是遍历文件列表,技术每一个数据文件出现的次数。此时时间复杂度为O(n),由于要存储每一个ID的计数信息所以空间复杂度也为O(n)。

       优化程序一般从时间复杂度和空间复杂度来考虑,很显然本题的时间复杂度没法再优化,只能尽可能优化空间复杂度。所以可以考虑用动态数组的方法,当遍历数据列表时,如果ID不在数组中就添加进去,如果数组中已存在对应的ID则从数组中删除相应的ID。这样空间复杂度就相应的减少了。这样就可以找出所有丢失的ID

      假设只有一个ID丢失,现在想要从中找出丢失的ID,利用异或方法(x^x=0,x^0=x,x^y=0),因为对应其他的ID数组中都有两个相同的值,异或运算满足交换律,结合律,所以对数组中的所有的ID进行异或运算,相同的ID异或后为0,则最后剩下的就是丢失的ID。

   

public static void second()
	{
		int[]  id = {1,2,3,1,2};
		int result = 0;
		for(int i = 0;i < id.length;i++)
		{
			result = result^id[i];
		}
		System.out.print(result);
	}

当有两个不同的ID丢失后,如何才能分别这两个ID,因为所有的ID异或之后得到的数是这两个丢失的ID异或而得到的。设x,y分别为丢失的ID,x与y异或的得到z(X^Y=Z),根据 Z的二进制表示从右到左第一个为1的位置b将所有的ID分成两类,一类为b位为1的一类为b位为0的,然后对两个类进行异或,得到x,y

//找出数组中仅出现一次的两个数
	public static void thrid()
	{
		int[]  id = {1,2,3,4,5,7,1,2,3,4};
		int result = 0;
		for(int i = 0;i < id.length;i++)
		{
			result = result^id[i];
		}
		int temp = result&1;
		int count = 0;
		while(temp == 0)
		{
			count++;
			result = result>>1;
		    temp = result&1;
		}		
		int i=0,j=0;
		for(int k = 0;k<id.length;k++)
		{
			int ptr = id[k]>>count;
		    if((ptr&1) == 0)
		    {
		    	i = i^id[k];
		    }
		    else
		    {
		    	j = j^id[k];
		    }
		}
		System.out.println(i);
		System.out.println(j);	
	}



    原文作者:GODBAR
    原文地址: https://blog.csdn.net/GODBAR/article/details/51584023
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞