zoukankan      html  css  js  c++  java
  • 59. 总结篇:数组中N(n=1,2,3)个只出现一次的数字[find N numbers which appear only once in array]

    【本文链接】

    http://www.cnblogs.com/hellogiser/p/find-n-numbers-which-appear-only-once-in-array.html

    题目】

    一个数组中有三个数字a、b、c只出现一次,其他数字都出现了两次。请找出三个只出现一次的数字。

    分析

    这是一道很新颖的关于位运算的面试题。在之前的博文34.数组中2个只出现一次的数字[Find two numbers which appear once]中分析了N=1和N=2的情况。

    (1).N=1时,数组所有数字异或的结果即为a。

    (2).N=2时,数组所有数字异或的结果等于a^b,根据a^b的二进制中最后一个1出现的位置,将数组分为2组;对每一组数字进行异或,即可求得a和b。

    (3).N=3时,数组所有数字异或的结果等于a^b^c。此时该如何区分呢?如果我们能够找出其中一个只出现一次的数字,剩下两个只出现一次的数字就可以转换为N=2的情况。

    具体思路如下:

    (1). f(x) = x & (-x)所得的结果即是x最后一位1所在的位置。

    (2). x = a ^ b ^ c。

    (3). flag = f(x^a)^f(x^b)^f(x^c) 结果必有一位是1,因为f(m)^f(n)结果为0或者为2个1。

    (4). f(x^a)^f(x^b)^f(x^c)的第m位为1,则x^a, x^b, x^c必有1个或者3个第m位为1。

    (5). 用反证法可得,x^a, x^b, x^c只有一个第m位为1。

    举个例子data={1,2,3,4,4,5,5,6,6}

    x = a ^ b ^ c =1^2^3 = 000

    x^a=001, x^b=010, x^c=011

    f(x^a)=001, f(x^b)=010, f(x^c)=001

    flag = f(x^a)^f(x^b)^f(x^c)=010,flag = f(flag)=010

    f(x^b)==flag

    first=b=1

    second=3,third=1

    完整代码如下:

    代码】

     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
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
     
    // 58_FindNumbersAppearOnce.cpp : Defines the entry point for the console application.
    //
    /*
        version: 1.0
        author: hellogiser
        blog: http://www.cnblogs.com/hellogiser
        date: 2014/5/27
    */


    #include "stdafx.h"

    // find number which appear once
    void Find1NumberAppearOnce(int data[], int length, int &num)
    {
        
    if(NULL == data || length < 1)
            
    return;

        
    // get the exclusive or result of array
        // a
        int xor = 0;
        
    for (int i = 0; i < length; ++i)
            
    xor ^= data[i];
        num = 
    xor;
    }

    // get last 1 bit of n
    // n=00001110--->00000010
    unsigned int GetLast1Bit(int n)
    {
        
    return n & (-n);
    }

    // find 2 numbers which appear once
    void Find2NumbersAppearOnce(int data[], int length, int &num1, int &num2)
    {
        
    if(NULL == data || length < 2)
            
    return;

        
    // get the exclusive or result of array
        // a^b
        int xor = 0;
        
    for (int i = 0; i < length; ++i)
            
    xor ^= data[i];

        
    // find the last bit 1 of xor
        int flag = GetLast1Bit(xor);
        num1 = num2 = 
    0;
        
    for(int j = 0; j < length; ++j)
        {
            
    // divide numbers in data into 2 groups by flag:
            // numbers in group1: the & result is 1
            // numbers in group2: the & result is 0
            if (flag & data[j])
            {
                num1 ^= data[j];
            }
            
    else
            {
                num2 ^= data[j];
            }
        }
    }

    // swap a and b
    void myswap(int &a, int &b)
    {
        
    int t = a;
        a = b;
        b = t;
    }

    // find 3 numbers which appear once
    /*
    (1). f(x) = x & (-x)
    (2). x = a ^ b ^ c
    (3). flag = f(x^a)^f(x^b)^f(x^c)
    (4). flag = f(flag)
    (5). x^a, x^b, x^c, only one of three is 1 at m-bit
      f(x^a)==flag

    for example:
      data={1,2,3,4,4,5,5,6,6}
      x = a ^ b ^ c =1^2^3 = 000
      x^a=001, x^b=010, x^c=011
      f(x^a)=001, f(x^b)=010, f(x^c)=001
      flag = f(x^a)^f(x^b)^f(x^c)=010
      flag = f(flag)=010
      f(x^b)==flag
      first=b=1
      second=3,third=1
    */

    void Find3NumbersAppearOnce(int data[], int length, int &num1, int &num2, int &num3)
    {
        
    if(NULL == data || length < 3)
            
    return;

        
    // get the exclusive or result of array
        // a^b^c
        int xor = 0;
        
    for(int i = 0; i < length; i++)
            
    xor ^= data[i];

        
    int flag = 0;
        
    for(int i = 0; i < length; i++)
            flag ^= GetLast1Bit(
    xor ^ data[i]);
        flag = GetLast1Bit(flag);

        
    // get the first unique number
        int first = 0;
        
    for(int i = 0; i < length; i++)
            
    if(GetLast1Bit(data[i] ^ xor) == flag)
                first ^= data[i];
        num1 = first;

        
    // move the first number to the end of array
        for(int i = 0; i < length; i++)
        {
            
    if (first == data[i])
            {
                myswap(data[i], data[length - 
    1]);
                
    break;
            }
        }

        
    // get the second and third unique number
        Find2NumbersAppearOnce(data, length - 1, num2, num3);
    }

    //=================================================================
    // test cases
    void test_base1(int data[], int length)
    {
        
    int num1;
        Find1NumberAppearOnce(data, length, num1);
        printf(
    "%d ", num1);
    }

    void test_base2(int data[], int length)
    {
        
    int num1, num2;
        Find2NumbersAppearOnce(data, length, num1, num2);
        printf(
    "%d %d ", num1, num2);
    }

    void test_base3(int data[], int length)
    {
        
    int num1, num2, num3;
        Find3NumbersAppearOnce(data, length, num1, num2, num3);
        printf(
    "%d %d %d ", num1, num2, num3);
    }

    void test_case1()
    {
        
    int data[] = {12233445566};
        
    int length = sizeof(data) / sizeof(int);
        test_base1(data, length);
    }

    void test_case2()
    {
        
    int data[] = {1233445566};
        
    int length = sizeof(data) / sizeof(int);
        test_base2(data, length);
    }

    void test_case3()
    {
        
    int data[] = {123445566};
        
    int length = sizeof(data) / sizeof(int);
        test_base3(data, length);
    }

    void test_main()
    {
        test_case1(); 
    // 1
        test_case2(); // 1 2
        test_case3(); // 2 3 1
    }
    //=================================================================

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

    【参考】

    http://www.cnblogs.com/hellogiser/p/3738909.html

    http://zhedahht.blog.163.com/blog/static/25411174201283084246412/

    http://www.cnblogs.com/youxin/p/3349834.html

    http://www.cnblogs.com/kedebug/archive/2012/12/22/2829013.html

    【本文链接】

    http://www.cnblogs.com/hellogiser/p/find-n-numbers-which-appear-only-once-in-array.html

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

    Author: hellogiser
    Warning: 本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。Thanks!
    Me: 如果觉得本文对你有帮助的话,那么【推荐】给大家吧,希望今后能够为大家带来更好的技术文章!敬请【关注】
  • 相关阅读:
    Win2008 Server MySql安装包详细安装教程
    ef codefirst VS里修改数据表结构后更新到数据库
    c#扩展方法
    c#异步学习笔记
    winform SerialPort串口通信问题
    委托与事件学习笔记
    泛型的优点
    c#泛型约束 (where T:class)
    .net扩展方法
    mvc5视图view不使用默认母版页
  • 原文地址:https://www.cnblogs.com/hellogiser/p/find-n-numbers-which-appear-only-once-in-array.html
Copyright © 2011-2022 走看看