需要在数组中找到一个唯一的数字
Need to find an unique number in an array
这就是问题所在(简而言之):
我们得到了一个具有N个自然数和一个val K的数组。我们需要在数组中查找一次出现的数字我数组中的任何其他数字都会出现K次。
我们需要找到那个数字。
限制和规范
200000<=N<=300000
2<=K<=15
我数组中的任何数字都是0。。。2^64-1
内存&执行时间限制:
内存:0.5 Mb
时间:0.6秒
示例:
Type:
N K
<array vals>
10 3
1 3 5 7 5 1 3 1 5 3
就是这样。我的主要问题是如何处理数组(0 ... 2^64-1
)中如此大的数字。
我的想法听起来是这样的(假设数字来自0 to 9
):
->我计算数组中每个数字的出现次数,并将其标记为计算值。
->我从0迭代到9,如果计算出数字(=我的数组中有这个数字),并且该数字的出现次数与K不同,我就解决了问题。
但是,我的数字来自0 to 2^64-1
,我不能声明2^64维的数组!
你们能给我个主意吗?
您可以在不到100字节的额外空间的快速线性时间内完成此操作。
如果K是偶数,那么只要将所有元素异或在一起,就完成了。
想想它是如何工作的——思考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;
额外信贷:如果您愿意的话,这个解决方案可以通过位并行添加进行优化(JSF的答案指向这个方向),但这可能不是您所需要的。您可以使用5个64位整数来表示每个计数器的低5位。在将这些计数器扩展到位值阵列之前,可以使用这些计数器累积多达31个输入值。积累每个单词看起来是这样的:
for (int i=0;i<5; i++)
{
uint64_t carry = parcounters[i]&val;
parcounters[i]^=val;
val=carry;
}
我认为输入是已读取的,但太大而无法存储。
因此,当您阅读它时,计算64位中的每一位设置了多少次位N。然后取这些计数中的每一个的余数mod K,对于每个比特位置,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:
a ^= x & ~(c & b);
z = x & ~a;
c ^= b & z;
b ^= z;
与11和13一起玩得开心。在所有情况下,最终答案都在a
中,没有额外的完成工作。如果没有错误或错误的输入,最后b
、c
和(如果需要的话)d
都将为零,所以这是一个简单的健全性检查。
也许我误解了这个问题,但这里有一种解决方法。
- 使用就地排序算法对数组进行排序。由于它已经就位,您将不需要比初始数组更多的空间。这比地图更节省空间
- 遍历数组,如果你找到一个没有重复的数字,那就是你的数字
您甚至可以通过在每个Kth元素上迭代并查看前一个数字是否不同来优化步骤2。(当目标数量是集合中最大或最小的数量时,您仍然必须处理特殊情况)
首先对数组进行排序,然后对其进行迭代以获得答案。这里是逻辑,唯一元素可以在标记为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;
}
- c++多进程编写一个唯一的文件
- 我需要编写一个程序来读取一个文件,该文件将输出所有唯一的整数,如果已经看到整数,它将被关闭
- 从另一个唯一 ptr 的原始 ptr 创建唯一的 ptr
- 如何在以 256 为基数的唯一 xLen-digit 表示中写一个整数 x?
- 需要在C 中生成一个从00001到99999的唯一5位数字
- 如何在给定任意数量的整数的情况下创建一个唯一键?并使用该键存储,然后从地图中查找
- 尝试创建一个读取.txt文件,显示它,计数唯一单词的程序,并在使用了多少次的情况下显示独特的单词.C
- 如何制作一个采用类型类的唯一指针?(通用)它不让我
- 为什么要在 c++ 中创建一个指向基元类型的唯一指针?
- 如何将唯一指针从一个向量移动到另一个唯一指针向量
- 将 n 个整数组合成一个唯一的表示形式
- 正确地返回一个唯一的ptr
- 为每个对象定义一个唯一的函数
- 需要在数组中找到一个唯一的数字
- 更快的方式,然后我填充一个唯一的整数除了两个值的向量?c++
- 如何将三个整数组合成一个唯一的标记,使标记在c++中保持整数
- 一个唯一的ptr类如何将它的实例指针传递给它的成员对象
- 试图在每次迭代中产生一个唯一的随机数序列
- 可变模板类:每个可变模板参数可以实现一个唯一的成员函数吗
- 如何将两个正整数映射为一个唯一的整数