• 找出2n+1个数中不成对的那个(升级版)


    上篇谈到了用异或来解决,确实是个好方法,时间复杂度为o(n),比例一遍ok,空间复杂度为o(1),只占用一个空间足矣。现在把这个问题升级下:

    (1)给出n个数,其中有且仅有一个出现了奇数次,其余的都出现了偶数次。用线性时间常数空间找出这个出现奇数次的数

    (2)给定n个数,其中有且仅有两个出现了奇数次,其余的都出现了偶数次。用线性时间常数空间找出这两个出现奇数次的数

    原理(原理不是很懂的,先看看上篇

    • 任何数和自己异或为0
    • 任何数和0异或为自己
    • 异或具有交换律

    思路

    (1)一个出现奇数次

    1. 出现偶数次的一异或为0了,对剩下的奇数次数不造成干扰
    2. 奇数次(2n+1)的前2n次一异或为0了,对剩下那个数不造成干扰
    3.  剩下的那个数就是结果

    (2)两个出现奇数次

    1. 常规的从头到尾异或一遍,得到数肯定不为0,这个数是那两个出现奇数次的数异或的结果
    2. 找出这个数中不为1的那个位pos(在这个位置处,两个奇数次的数肯定不同——要是相同这个位也是0)
    3. 整个序列根据位pos的值分成两组(0的一组,1的一组,这样把出现偶数次的分到一组,无碍。出现奇数次的分到两组,正好)
    4. 对着两组,利用(1)的方法,解决

    细节:如何找到一个二进制中第一个是"1"的位

     1 #include <stdio.h>
     2 
     3 #define N 10
     4 
     5 int main()
     6 {
     7         int a[N] = {2, -11, -11, 2, 43, 5, 564, 43, 5, -3};
     8         int i, t;
     9         int pos = 0, left = 0, right = 0; // remember to initilize!
    10 
    11         t = a[0];
    12         for (i = 1; i < N; i++)
    13                 t ^= a[i];
    14 
    15         while (t % 2 == 0) {
    16                 t >>= 1;
    17                 pos++;
    18         }
    19 
    20         for (i = 0; i < N; i++) {
    21                 if (a[i] & (1 << pos))
    22                         left ^= a[i];
    23                 else
    24                         right ^= a[i];
    25         }
    26 
    27         printf("they are: %d & %d
    ", left, right);
    28 
    29         return 0;
    30 }
  • 相关阅读:
    Resize a VMWare disk (zz)
    StepbyStep: Installing SQL Server Management Studio2008 Express after Visual Studio 2010(zz)
    (C#)利用反射动态调用类成员[转载]
    Discuz!NT 系统架构分析 (转)
    C#反射实例讲解(转)
    什么是反射?
    创建保存图片目录
    取资源文件中的值 System.Resources.ResourceManager
    Net中的反射使用入门
    iis上实现虚拟目录
  • 原文地址:https://www.cnblogs.com/szhan/p/3174244.html
Copyright © 2020-2023  润新知