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