zoukankan      html  css  js  c++  java
  • 61. 从1到n,共有n个数字,每个数字只出现一次。从中随机拿走一个数字x,请给出最快的方法,找到这个数字。如果随机拿走k(k>=2)个数字呢?[find k missing numbers from 1 to n]

    【本文链接】

    http://www.cnblogs.com/hellogiser/p/find-k-missing-numbers-from-1-to-n.html

     【题目】

    从1到n,共有n个数字(无序排列),每个数字只出现一次。现在随机拿走一个数字x,请给出最快的方法,找到这个数字。要求时间复杂度为O(n),空间复杂度为O(1)。如果随机拿走k(k>=2)个数字呢?

    【分析】

    题目给出的条件很强,数字是从1~n的数字,限制了数字的范围;每个数字只出现一次,限制了数字出现的次数;随即拿走了一个数字,说明只有一处是与其他不同、不符合规律的。我们可以利用这些特点来选择合适的解法。

    (1)Hash法。利用Hash法统计数字出现的次数,次数为0的即为所求。时间复杂度O(n),空间复杂度O(n)。通常这不是面试、笔试时想要的答案,但是Hash的优势在于其通用性。

    (2)排序法。利用快排,得到排序后的数组,然后顺序遍历,统计次数为0的数字。时间复杂度O(nlgn),空间复杂度O(1)。其时间复杂度略高,通常也不是面试官期待的解法,但排序法也算是一种通用做法。

    (3)元素相乘/相加法。时间复杂度O(n),空间复杂度O(1)。

    元素相乘法:由于只有一个元素被拿走,因此我们只需要先算出n的阶乘n!,再除以现存所有数字的乘积M,即可得到拿走的数字x (x=n!/M)。但是且缺陷是n不能太大,否则会溢出。

    元素相加法:先算出从1到n的所有数字的和Sn,然后减去现有所有数字的和sum,即可得到拿走的数字x(x=Sn-sum)。元素相加法比元素相乘要更好一些。

    (4)位运算时间复杂度O(n),空间复杂度O(1)。

    位运算法如果可以使用的话,应该是计算最快的方法。但是位运算对条件要求也较苛刻,一般需要元素有特殊规律,才有可能使用这种方法。在本题目中,对1~n所有元素进行xor运算得到A=1^2^3^…^(x-1)^x^(x+1)^…^n,在对取走一个元素后剩下的元素进行xor运算得到B=1^2^3^…^(x-1)^(x+1)^…^n,二者xor即可得拿走的数字x = A^B。因为在A^B的过程中相同的数字都被抵消掉了,剩余的结果即为x。

    【代码】

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
     
    // 61_FindMissingNumberFrom1toN.cpp : Defines the entry point for the console application.
    //
    /*
        version: 1.0
        author: hellogiser
        blog: http://www.cnblogs.com/hellogiser
        date: 2014/5/28
    */


    #include "stdafx.h"

    /*
    A=1^2^3^...^(x-1)^x^(x+1)^...^n
    B=1^2^3^...^(x-1)^(x+1)^...^n
    x = A^B

    n=9
    1,2,3,4,6,7,8,9
    x = 5
    */

    int FindMissingNumberFrom1ToN(int data[], int n)
    {
        
    int length = n - 1;
        
    if(NULL == data || length <= 0)
            
    return -1;
        
    // xor all
        int xor_all = 0;
        
    for(int i = 1; i <= n; i++)
            xor_all ^= i;

        
    // xor of current array
        int xor_current = 0;
        
    for(int i = 0; i < length; i++)
            xor_current ^= data[i];

        
    //get result
        int result = xor_all ^ xor_current;
        
    return result;
    }

    void test_base(int data[], int n)
    {
        
    int result = FindMissingNumberFrom1ToN(data, n);
        printf(
    "%d  ", result);
    }

    void test_case1()
    {
        
    int data[] = {123};
        
    int length = sizeof(data) / sizeof(int);
        test_base(data, length + 
    1);
    }

    void test_case2()
    {
        
    int data[] = {234};
        
    int length = sizeof(data) / sizeof(int);
        test_base(data, length + 
    1);
    }

    void test_case3()
    {
        
    int data[] = {12346789};
        
    int length = sizeof(data) / sizeof(int);
        test_base(data, length + 
    1);
    }

    void test_main()
    {
        test_case1();
        test_case2();
        test_case3();
    }

    int _tmain(int argc, _TCHAR *argv[])
    {
        test_main();
        
    return 0;
    }
    /*
    4
    1
    5
    */

    【扩展】

    如果随机拿走两个数字呢?如果随机拿走k(k>2)个数字呢?

    (1)(2)是通用做法,仍适合。

    (3)扩展:

    K=1时,构造2个等式。

    Sa = 1+2+…(x-1)+x+(x+1)…+n

    Sb = 1+2+…(x-1)+(x+1)…+n

    X = Sa-Sb

    K=2时,构造4个等式。

    S2a = 12+22+…+x2+…+y2+…+n

    S2b = 12+22+…(x-1)2+(x+1)2…+(y-1)2+(y+1)2…+n

    S1a = 1+2+…+x+…+y+…+n

    S1b = 1+2+…(x-1)+(x+1)…+(y-1)+(y+1)…+n

    则有x2+y2=S2a-S2b,x+y =S1a-S1b。可以求解得到x和y。

    同理(k>2),构造2*k个等式,可以得到关于k个数的k个方程,求解即可得到k个数字。

    (4)扩展:

    思考一下,如何扩展?

    【参考】

    http://ouscn.diandian.com/post/2013-10-06/40052170552

    【本文链接】

    http://www.cnblogs.com/hellogiser/p/find-k-missing-numbers-from-1-to-n.html

    个人学习笔记,欢迎拍砖!---by hellogiser

    Author: hellogiser
    Warning: 本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。Thanks!
    Me: 如果觉得本文对你有帮助的话,那么【推荐】给大家吧,希望今后能够为大家带来更好的技术文章!敬请【关注】
  • 相关阅读:
    SQL 分组 行变列的一个例子
    用JS如何獲得DropDownList所選Text和Value?
    用了.net2.0,再用1.1的问题。1.1里修改.cs文件不重新编译,.dll不重新生成。
    ASP.NET中上传文件
    获得用户控件的值!
    在没有vs2005环境里部署Crystal Reports 10水晶报表
    onkeypress,onkeydown,onkeyup区别
    2012湖南大学第八届程序设计竞赛 Incredible[公式]
    POJ3624 Charm Bracelet[01背包问题入门]
    HDOJ1257 最少拦截系统[DP入门]
  • 原文地址:https://www.cnblogs.com/hellogiser/p/find-k-missing-numbers-from-1-to-n.html
Copyright © 2011-2022 走看看