C++ 需要在数组中找到唯一的数字

C++ 需要在数组中找到唯一的数字,c++,algorithm,implementation,C++,Algorithm,Implementation,这就是问题所在(简而言之): 我们得到了一个包含N个自然数和一个值K的数组。我们需要 在数组中查找一次出现的数字 我的数组中的任何其他数字都会精确显示K次 我们需要找到那个号码 限制和规范 200.000也许我误解了这个问题,但这里有一个解决方法 使用就地排序算法对数组进行排序。因为它已经就位,所以您不需要比初始数组更多的空间。这比地图更节省空间 迭代数组,如果找到一个没有重复的数字,那就是你的数字 您甚至可以通过迭代每个第k个元素并查看前面的数字是否不同来优化步骤2。(当目标数字是集合中最大或

这就是问题所在(简而言之):

我们得到了一个包含N个自然数和一个值K的数组。我们需要 在数组中查找一次出现的数字 我的数组中的任何其他数字都会精确显示K次

我们需要找到那个号码

限制和规范


200.000也许我误解了这个问题,但这里有一个解决方法

  • 使用就地排序算法对数组进行排序。因为它已经就位,所以您不需要比初始数组更多的空间。这比地图更节省空间
  • 迭代数组,如果找到一个没有重复的数字,那就是你的数字

  • 您甚至可以通过迭代每个第k个元素并查看前面的数字是否不同来优化步骤2。(当目标数字是集合中最大或最小的数字时,您仍然必须处理特殊情况)

    我假设输入已读取,但太大而无法存储

    因此,在阅读时,计算64位中的每一位设置了多少次位N。然后取每个计数的剩余值mod K,对于每个位位置,该值为零或一,给出该位位置的值

    如果您不介意编写大量繁琐的代码,您可以编写六个不同的布尔模计数例程,并根据K的最低素数因子选择其中一个:2、3、5、7、11或13

    这避免了64位上的所有循环,对于2,速度应该快64倍以上,对于最坏的情况13,速度可能仍然快8倍以上

    例如,布尔计数mod 3可以通过以下方式完成: 在循环
    a=b=0
    之前,然后对于每个输入
    x

    z = a | b;
    a ^= x & ~b;
    b ^= x & z;
    
    最后,结果是
    a

    对于5,您可以从
    a=b=c=0开始,并使用:

    b ^= x & a;
    a ^= x & ~c;
    c ^= x & ~(a|b);
    
    7:


    享受11和13的乐趣。在所有情况下,最终答案都在
    a
    中,没有额外的完成工作。如果没有错误或错误输入,那么在
    b
    c
    和(如果需要的话)
    d
    的末尾都将为零,因此这是一个简单的健全性检查。

    您可以用不到100字节的额外空间在快速线性时间内完成这项工作

    如果K是偶数,那么只需将所有元素XOR在一起,就完成了

    想想它是如何工作的——考虑xor操作的一种方式是,它将每一位都视为一个独立的数字。它将它们相加并生成mod 2的结果。任何与偶数相乘的值都是0 mod 2,因此只有在出现一次的数字中设置的位保持设置

    如果K不是偶数,那么你可以做同样的工作,但是mod K(或K的因子——3或5)代替mod 2

    鉴于:

    int K,N;  //input values
    uint64_t data[N]; //array of numbers
    
    代码如下所示:

    //initialize a counter for each bit in the result
    int bitvals[64];
    for (int bit=0; bit<64; ++bit)
    {
        bitvals[bit]=0;
    }
    
    //count the number of times each bit occurs in the array
    for(int i=0; i<N; ++i)
    {
        uint64_t val=data[i];
        for(int bit=0; bit<64; ++bit)
        {
            if (val & (((uint64_t)1)<<bit))
                bitvals[bit]+=1;
        }
    }
    
    //only the bits in the number that occurs once are non-zero mod K
    //make that number
    uint64_t ret=0;
    for(int bit=0; bit<64; ++bit)
    {
        if (bitvals[bit]%K)
            ret |= ((uint64_t)1)<<bit;
    }
    return ret;    
    
       for (int i=0;i<5; i++)
       {
          uint64_t carry = parcounters[i]&val;
          parcounters[i]^=val;
          val=carry;
       }
    
    //为结果中的每个位初始化计数器
    整数位数[64];
    
    对于(int bit=0;bit首先对数组进行排序,然后对其进行迭代以获得答案。根据逻辑,唯一元素可以位于标记为0,K,2K,3K,…,N-1的任何位置

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    unsigned long long uniqueNumber(vector<unsigned long long> &arr, int K) {
        sort(arr.begin(), arr.end());
        int i = 0;
        for(i = K-1;i < arr.size();i += K) {
            if(arr[i] != arr[i-K+1])
                return arr[i-K+1];
        }
        return arr[i-K+1];
    }
    
    int main()
    {
        vector<unsigned long long> A{1, 3, 5, 7, 5, 1, 3, 1, 5, 3};
        cout<<uniqueNumber(A, 3)<<endl;
        return 0;
    }
    
    #包括
    #包括
    使用名称空间std;
    无符号长唯一数(向量&arr,整数K){
    排序(arr.begin(),arr.end());
    int i=0;
    对于(i=K-1;i
    cout“如何处理我的数组(0…2^64-1)中的如此大的数字。”用<代码> uTunt64→和 > < <代码> >你想得到一个<代码>位图< /C>。不可以想一想你的确切解决方案或算法,如果我做了,请报告。请选择C和C++最多的一个。这看起来像是作业或挑战。找到解决方案是你的测试的一部分。所以你应该从皮奇开始。定义一种语言并研究该语言提供的内容。不需要数组大小(2^64)-1.问题是
    200.000不理解下一票。它比简单的std::map更复杂,但它是另一个明显的解决方案。@MartinBonner:事实上,它是更有效的版本。只是不清楚数组是否可以修改。就地排序算法?@SimCard你能详细说明吗?就地意味着你不能排序所需的内存不仅仅是常量。一种可以就地实现的常见排序是快速排序。因此,本质上,您可以使用原始数组的空间进行排序。谢谢您的回答!您可以发布代码吗?我会考虑并尝试实现它,并对其进行比较。方法不错,但如果K为偶数,它会直接生成结果。不是确定你对
    mod 2
    的意思。不确定这是否适用于奇数
    K
    (顺便说一句:请在文本中添加格式).你能详细说明吗?@Tib:如果他提供了代码,你就没有什么可以实现的了。这是一个非常好的方法。我认为你不应该真正提供代码;OP应该自己做一些事情。好吧,我认为这是一个类似于@matttimmermans的方法,但我认为这更详细。我该怎么做:“计算64位中的每一位设置了多少次位N。然后将剩余的数取为mod K”@Olaf我真的很感谢你的评论,谢谢你来到这里!@Tib:好的,我给你最后一个提示:如果数组[N],设置位I>然后设置cntr[I]+
    ,你需要类似于
    的东西。(这是某种元语言,显然不是C++)。@Olaf元语言?从未听说过:)无论如何,再次感谢!效率低下,不清楚数组是否可以修改。我同意这不是一种有效的方法。但我认为这种方法是正确的。如果我在某个地方出错,请纠正我。数组的副本将被修改而不是实际的数组。如果复制数组,则违反了大小约束。排序可能违反时间约束。
    
       for (int i=0;i<5; i++)
       {
          uint64_t carry = parcounters[i]&val;
          parcounters[i]^=val;
          val=carry;
       }
    
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    unsigned long long uniqueNumber(vector<unsigned long long> &arr, int K) {
        sort(arr.begin(), arr.end());
        int i = 0;
        for(i = K-1;i < arr.size();i += K) {
            if(arr[i] != arr[i-K+1])
                return arr[i-K+1];
        }
        return arr[i-K+1];
    }
    
    int main()
    {
        vector<unsigned long long> A{1, 3, 5, 7, 5, 1, 3, 1, 5, 3};
        cout<<uniqueNumber(A, 3)<<endl;
        return 0;
    }