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


目录(?)[-]

  1. 问题11N的自然数中少了一个找出这个数
  2. 问题21N个自然数少了两个找出这两个数
  3. 问题3给你n个数其中有且仅有一个数出现了奇数次其余的数都出现了偶数次用线性时间常数空间找出出现了奇数次的那一个数
  4. 问题4给你n个数其中有且仅有两个数出现了奇数次其余的数都出现了偶数次用线性时间常数空间找出出现了奇数次的那两个数


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

(1)求和-容易溢出

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

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


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


    (2)异或^

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

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


    1. public int find_Miss_Number_By_XOR(int array[], int
    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. 1);  
    11.     }  
    12. return
    13.   
    14. }


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

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


      1. public int find_Miss_Number_By_Sort(int array[], int
      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. 1] = array[i];  
      11.     }  
      12. for (int i = 0; i < b.length; i++) {  
      13. if (b[i] == 0) {  
      14. 1;  
      15. break;  
      16.         }  
      17.     }  
      18. return
      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


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

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


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

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


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

      (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的分到另一类。对每一类分别使用前一个问题的算法。 

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

      1. public static void
      2. 1,1,2, 2, 3,3,4, 4, 5,5,};  
      3. 1, 2,2, 3,4, 4, 5,5,};  
      4.     getMissNumber(array, subArray);  
      5. }