1-N的自然数中,少了一个,找出这个数

来源:互联网 发布:dreamweaver这软件怎样 编辑:程序博客网 时间:2024/05/16 16:15

问题1:1-N的自然数中,少了一个,找出这个数

(1)求和-容易溢出

Sum=1+2+...+N=(N+1)N/2,然后遍历数列每次从S1中减去当前的数字,最后剩下的数字就是所求。

为了防止溢出我们可以每次在S1大于一定的数字后,就去减,然后继续求和,再大于就继续减,以此类推。

[java] view plaincopyprint?
  1. public int find_Miss_Number_By_Sum(int array[], int n) {  
  2.     int sum = 0;  
  3.     if (array.length != n - 1)  
  4.         throw new IllegalArgumentException("数组内的自然数目少于n-1");  
  5.     for (int i : array) {  
  6.         sum += i;  
  7.     }  
  8.     return n * (n + 1) / 2 - sum;  
  9. }  

(2)异或^

Y=1^2^3...^N,然后遍历数列每次异或当前的数字,最后剩下的就是要求的数字

任何数异或自己都等于0,任何数异或0都等于他自己

[java] view plaincopyprint?
  1. public int find_Miss_Number_By_XOR(int array[], int n) {  
  2.     int result = 0;  
  3.     if (array.length != n - 1)  
  4.         throw new IllegalArgumentException("数组内的自然数目少于n-1");  
  5.       
  6.     for (int i = 0; i < array.length; i++) {  
  7.         result = result  ^ array[i];  
  8.     }  
  9.     for (int i = 0; i < n; i++) {  
  10.         result=result^(i+1);  
  11.     }  
  12.     return result;  
  13.   
  14. }  

(3)O(N)时间的移动-排序

将a[i]移动到b[a[i]],使得数组有序,然后找出空着的位置

[java] view plaincopyprint?
  1. public int find_Miss_Number_By_Sort(int array[], int n) {  
  2.     int result = 0;  
  3.   
  4.     if (array.length != n - 1)  
  5.         throw new IllegalArgumentException("数组内的自然数目少于n-1");  
  6.   
  7.     int b[] = new int[n];  
  8.   
  9.     for (int i = 0; i < array.length; i++) {  
  10.         b[array[i] - 1] = array[i];  
  11.     }  
  12.     for (int i = 0; i < b.length; i++) {  
  13.         if (b[i] == 0) {  
  14.             result = i + 1;  
  15.             break;  
  16.         }  
  17.     }  
  18.     return result;  
  19. }  

(4)O(NlogN)时间的移动-排序

用快排的思想,在1-N中选取游标X对数组快排一次,如果X被放在a[X-1]的位置上那么,要找的数字在X-N之间

否则X被放在a[X-2]的位置上 要找的数字在1-X-1之间   递归求解,直到找的要找的数字。

 

 

问题2:1-N个自然数,少了两个,找出这两个数

(1)求和-容易溢出

S1=1+2+...+N=(N+1)N/2

S2=12+22+...+N2=(N+1)(2N+1)N/6

[java] view plaincopyprint?
  1. import junit.framework.TestCase;  
  2.   
  3. public class Find_Miss_Numbers_By_Sum_And_Mul extends TestCase {  
  4.       
  5.     //1-N的自然数中,少了一个,找出这个数   
  6.     //方法:求和,求积  x1+x2 和 x1*x2都知道了以后,求出x1和x2  
  7.     public void find_Miss_Number_By_Sum_and_Product(Integer array[]) {  
  8.   
  9.         int sum = 0//保存缺少的两个数的和  
  10.         int product = 1;//保存缺少的两个数的积  
  11.         int n = array.length + 2;  
  12.   
  13.         // 1-n的自然数的和减去数组中所有元素的和,即为缺少的两个数之和  
  14.         for (Integer i : array) {  
  15.             sum += i;  
  16.         }  
  17.         sum = n * (n + 1) / 2 - sum;  
  18.   
  19.         // 1-n的自然数的积除以数组中所有元素,即为缺少的两个数之积  
  20.         for (int j = 1; j < n + 1; j++) {  
  21.             product = product * j;  
  22.         }  
  23.         for (Integer integer : array) {  
  24.             product /= integer;  
  25.         }  
  26.         System.out.println("数组元素的和为" + sum);  
  27.         System.out.println("数组元素的积为" + product);  
  28.         System.out.println("缺少的第一个数为" + getSolution_left(sum, product));  
  29.         System.out.println("缺少的第二个数为" + getSolution_right(sum, product));  
  30.   
  31.     }  
  32.     // 根据x1+x2 和 x1*x2都x1和x2  
  33.     public int getSolution_left(int sum, int product) {  
  34.         return (int)(sum - Math.sqrt(sum * sum - 4 * product)) / 2;  
  35.   
  36.     }  
  37.     public int getSolution_right(int sum, int product) {  
  38.         return (int) (sum + Math.sqrt(sum * sum - 4 * product)) / 2;  
  39.     }  
  40.   
  41.     public void test() {  
  42.         Integer a[] = { 1235789 };  
  43.         find_Miss_Number_By_Sum_and_Product(a);  
  44.     }  
  45.   
  46. }  

对于少了K个数的情况,如果K很少,我们可以找出K个和上面类似的函数,计算总体值,然后用解K元一次方程得到结果,但要注意函数的选择

(2)异或

按照上面同样的方法,求出最后的值P等于两个数的异或

确定P从低位到高位的第一个1是第i位,现在用快排的思想,将数列分成两个区间A和B,其中A中第i位是0,B中的第i位是1,然后1-N中第i位是0的异或A,最后的结果就为缺少的第一个数。同理在B中求出第二个数(也可在求出第一个数后,用该数异或P,结果即为缺少的第二个数)。

[java] view plaincopyprint?
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. import junit.framework.TestCase;  
  5.   
  6. public class Find_Miss_Numbers_By_Xor extends TestCase {  
  7.   
  8.     /** 
  9.      * @param array 包含所有整数的数组 
  10.      * @param subArray 缺少整数的数组 
  11.      * @return 缺少的整数的异或值 
  12.      */  
  13.     public static int find_Miss_Number_By_XOR(Integer array[],Integer subArray[]) {  
  14.         int result = 0;  
  15.   
  16.         for (Integer e : array) {  
  17.             result ^= e;  
  18.         }  
  19.         for (Integer e : subArray) {  
  20.             result ^= e;  
  21.         }  
  22.         return result;  
  23.     }  
  24.   
  25.     // 获取最低位1的位置  
  26.     public static int get_mid_By_xor_result(int number) {  
  27.         int location = 0;  
  28.         while (number % 2 == 0) {  
  29.             location++;  
  30.             number /= 2;  
  31.         }  
  32.         return location;  
  33.     }  
  34.    //返回一个数组中第i位为1的所有的数构成的数组  
  35.     private static Integer[] divid_Array(Integer array[], int i) {  
  36.   
  37.         List<Integer> list = new ArrayList<Integer>();  
  38.   
  39.         for (Integer e : array) {  
  40.             int temp = e;  
  41.               
  42.             for (int j = 0; j < i; j++) {  
  43.                 temp = e / 2;  
  44.             }  
  45.             if (temp % 2 == 1) {  
  46.                 list.add(e);  
  47.             }  
  48.   
  49.         }  
  50.         Integer[] result = new Integer[list.size()];  
  51.         for (int j = 0; j < list.size(); j++) {  
  52.             result[j] = list.get(j);  
  53.         }  
  54.         return result;  
  55.     }  
  56.   
  57.     /** 
  58.      * @param array 包含所有整数的数组 
  59.      * @param subArray 缺少整数的数组 
  60.      */  
  61.     public static void getMissNumber(Integer array[], Integer subArray[]) {  
  62.         int xor = find_Miss_Number_By_XOR(array, subArray);  
  63.         System.out.println("异或的结果为" + xor);  
  64.         int mid = get_mid_By_xor_result(xor);  
  65.         System.out.println("最低位1的位置" + mid);  
  66.         // 数组A的元素为:  
  67.         System.out.println("数组A的元素为:");  
  68.         Integer[] array1 = divid_Array(array, mid);  
  69.         for (Integer e : array1) {  
  70.             System.out.print(e + "、");  
  71.         }  
  72.         // 数组B的元素为:  
  73.         System.out.println();  
  74.         System.out.println("数组B的元素为:");  
  75.         Integer[] array2 = divid_Array(subArray, mid);  
  76.         for (Integer e : array2) {  
  77.             System.out.print(e + "、");  
  78.         }  
  79.         System.out.println();  
  80.         System.out.println("缺少的第一个数为:");  
  81.         int solution1 = find_Miss_Number_By_XOR(array1, array2);  
  82.         System.out.println(solution1);  
  83.         System.out.println("缺少的第二个数为:");  
  84.         int solution2 = solution1 ^ xor;  
  85.         System.out.println(solution2);  
  86.   
  87.     }  
  88.   
  89.     public static void main(String[] args) {  
  90.         Integer array[] = { 123456789,10,11,12};  
  91.         Integer subArray[] = { 12,  456789,11,12 };  
  92.         getMissNumber(array, subArray);  
  93.     }  
  94.   
  95. }   

(3)O(N)时间移动-排序

跟上面一样,实际上这种方法对于少了K个数的情况都能适用。

[java] view plaincopyprint?
  1. import junit.framework.TestCase;  
  2.   
  3. public class Find_Miss_Numbers_By_Move extends TestCase {  
  4.   
  5.     // 1-N的自然数中,少了一个,找出这个数  
  6.     // 方法:将a[i]移动到a[a[i]],使得数组有序,然后找出空着的位置  
  7.     public void find_Miss_Number_By_Move(int array[], int n) {  
  8.   
  9.         int b[] = new int[n];  
  10.         for (int i : array) {  
  11.             b[i - 1] = i;  
  12.         }  
  13.   
  14.         System.out.print("数组的元素为:");  
  15.         for (int j : b) {  
  16.             if (j != 0) {  
  17.                 System.out.print(j + "、");  
  18.             }  
  19.         }  
  20.           
  21.         System.out.println();  
  22.         System.out.print("缺少的数为:");  
  23.         for (int k = 0; k < b.length; k++) {  
  24.             if (b[k] == 0) {  
  25.                 System.out.print(k + 1 + "、");  
  26.             }  
  27.         }  
  28.   
  29.     }  
  30.   
  31.     public void test() {  
  32.         int a[] = { 124789 };  
  33.         find_Miss_Number_By_Move(a, 9);  
  34.     }  
  35.   
  36. }  

(4)O(NlogN)时间移动-排序

跟上面的方法一样

如果X被放在a[X-1]位置上,要找的两个数字在X-N之间

如果X被放在a[X-2]位置上,要找的数字一个在1-X-1间,一个在X-N之间

如果X被放在a[X-3]位置上,要找的数字都在1-X-1间

对于少了K个数字的情况,这种方法也可以做,但实现起来就比较复杂了

 

问题3:给你n个数,其中有且仅有一个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那一个数。

(1)异或

一个数跟自己偶数次异或是0,奇数次异或是自己

 

问题4:给你n个数,其中有且仅有两个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那两个数。

从头到尾异或一遍,你就得到了需要求的两个数异或后的值。这两个数显然不相等,异或出来的结果不为0。我们可以据此找出两个数的二进制表达中不同的一位,然后把所有这n个数分成两类,在那一位上是0的分成一类,在那一位上是1的分到另一类。对每一类分别使用前一个问题的算法。 

代码和异或找两个数一样,将测试数据该成即可

[java] view plaincopyprint?
  1. public static void main(String[] args) {  
  2.     Integer array[] = { 1,1,223,3,445,5,};  
  3.     Integer subArray[] = {  12,23,445,5,};  
  4.     getMissNumber(array, subArray);  
  5. }

转http://blog.csdn.net/ncepuzhuang/article/details/8719341

0 0