zoukankan      html  css  js  c++  java
  • 由n个元素组成的数组,n-2个数出现了偶数次,两个数出现了奇数次,且这两个数不相等,如何用O(1)的空间复杂度,找出这两个数

    思路分析:

        方法一:涉及到两个数,就要用到异或定理了:若a^b=x,则a=b^x,b=x^a。对于这道题,假设这两个数分别为a、b,将数组中所有元素异或之后结果为x,因为a!=b,所以x=a^b,且x!=0,判断x中位为1的位数,只需要知道某一个位为1的位数k,如00101100,k可以取2或者3,或者5.因为x中第k位为1表示a或b中有一个数的第k位也为1,假设为a,将x与数组中第k位为1的数进行异或时,也即将x与a以及其他第k位为1的出现过偶数次的数进行异或,化简即为x与a异或,最终结果即为b。

    程序示例如下:

    #include "stdafx.h"
    #include <stdio.h>
    void FindElement(int a[], int length)
    {
        if (a == NULL || length <= 0)
            printf("数组中无元素,找个毛啊。");
        else
        {
            int s = 0;
            int i;
            int k = 0;
            for (i = 0; i < length; i++)
            {
                s = s^a[i];
            }
            int s1 = s;
            int s2 = s;
            while (!(s1 & 1))
            {
                s1 = s1 >> 1;
                k++;
            }
            for (i = 0; i < length; i++)
            {
                if ((a[i] >> k) & 1)
                    s = s^a[i];            
            }
            printf("%d %d
    ", s, s^s2);
        }    
    }
    int main()
    {
        int array[] = { 1, 2, 2, 3, 3, 4, 1, 5 };
        int len = sizeof(array) / sizeof(array[0]);
        FindElement(array, len);
        getchar();
        return 0;
    }

        效果如图:

        方法二:如果能够把原数组分为两个子数组,在每个子数组中,包含一个只出现一次的数字,而其他数字都出现两次,问题就可以很容易的解决了:分别对两个子数组执行异或运算。

    首先从头到尾依次异或数组中的每一个数字,因为其他数字都出现了两次,在疑惑中全部抵消掉了,所以最终得到的结果将是两个只出现一次的数字的异或结果。而这两个数字肯定不一样,那么这个异或结果肯定不为0,也就是说在这个结果数字的二进制表示中至少就有一位为1,否则就为0了。在结果数字中找到第一个为1的位的位置,记为第N位,那么这两个数字一个第N位为1,另一个第N位为0,这样异或后结果数字的第N位才能为1.此时以第N位是不是1为标准把原数组中的数字分为两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0.通过这种方法就可以把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其他数字都出现了两次。

    代码如下:

    #include "stdafx.h"
    #include <stdio.h>
    void findOnce(int data[], int n, int &num1, int &num2)
    {
        if (n < 5)
            return;
        int r1 = 0;
        for (int i = 0; i < n; i++)
            r1 = r1^data[i];
        int bitNum = 0;
        while (!(r1 & 0x1))
        {
            r1 = r1 >> 1;
            bitNum++;
        }
        int flag = (1 << bitNum);
        num1 = 0;
        num2 = 0;
        for (int j = 0; j < n; j++)
        {
            if (data[j] & flag)
                num1 = num1^data[j];
            else
                num2 = num2^data[j];
        }
    }
    int main()
    {
        int array[] = { 1, 2, 3, 2, 4, 3, 5, 1 };
        int num1, num2;
        findOnce(array, sizeof(array) / sizeof(array[0]), num1, num2);
        printf("%d
    %d
    ", num1, num2);
        getchar();
        return 0;
    }

        效果如图:

  • 相关阅读:
    LED点阵显示
    KEIL安装
    KEIL安装
    ubuntu安装svn
    python基础-面向过程编程
    js遇到代码出现问题时如何调试代码
    js内置对象的常用属性和方法(Array | String | Date | Math)
    js函数的使用+封装+代码复用
    JavaScript中条件分支语句和循环语句的使用,用简洁的代码实现强大功能
    JavaScript的语法、数据类型、基本算数和逻辑运算操作
  • 原文地址:https://www.cnblogs.com/cysolo/p/3600088.html
Copyright © 2011-2022 走看看