生成一个不同于数组中1000个元素的新元素
Generate a new element different from 1000 elements of an array
我在一次采访中被问到这个问题。考虑穿孔卡片的场景,其中每个穿孔卡片都有64位模式。有人建议我把每张卡都作为int
,因为每个int都是一个位的集合。
此外,考虑到我有一个数组,其中已经包含1000张这样的卡片。我每次都要生成一个新的元素,这与之前的1000张卡不同。数组中的整数(又名卡片(不一定要排序。
更重要的是,对于C++来说,这怎么可能呢?64 bit int
来自哪里?我如何从要生成的元素与数组中已经存在的所有元素不同的数组中生成这个新卡?
有2个6464位整数,这个数字太多了大于1000,最简单的解决方案是只生成随机64位数字,然后验证它是否不在的表中已经生成的数字。(可能性是无穷小,但你也可以确定。(
由于大多数随机数生成器不会生成64位值,因此剩下的要么自己写,要么(简单得多(结合值,比如生成8个随机字节,然后memcpy
将它们转换为uint64_t
。
至于验证号码是否已经存在,std::find
为只适用于一两个新数字;如果你必须做很多查找、排序表和使用二进制搜索值得的或者某种哈希表。
我可能遗漏了一些东西,但大多数其他答案在我看来过于复杂。只需对原始数组进行排序,然后从零开始计数:如果当前计数在数组中,请跳过它,否则您就有了下一个数字。这个算法是O(n(,其中n是新生成的数字的数量:对数组进行排序和跳过现有数字都是常数。这里有一个例子:
#include <algorithm>
#include <iostream>
unsigned array[] = { 98, 1, 24, 66, 20, 70, 6, 33, 5, 41 };
unsigned count = 0;
unsigned index = 0;
int main() {
std::sort(array, array + 10);
while ( count < 100 ) {
if ( count > array[index] )
++index;
else {
if ( count < array[index] )
std::cout << count << std::endl;
++count;
}
}
}
这里有一个O(n(算法:
int64 generateNewValue(list_of_cards)
{
return find_max(list_of_cards)+1;
}
注意:正如@amit在下面指出的,如果INT64_MAX
已经在列表中,则此操作将失败
据我所知,这是获得O(n(的唯一方法。如果你想处理(相当重要的(边缘情况,那么你必须进行某种适当的排序或搜索,这将带你进入O(n log n(。
@arne就快到了。您需要的是一个自平衡区间树,它可以在O(nlgn(时间内构建。
然后取顶部节点,它将存储一些区间[i,j]。根据区间树的性质,i-1和j+1都是新密钥的有效候选者,除非i=UINT64_MIN
或j=UINT64_MAX
。如果两者都为真,那么您已经存储了2^64个元素,并且不可能生成新的元素。存储新元素,这需要O(lgn(最坏的时间。
即:init取O(nlgn(,generate取O(lgn(。两者都是最坏的情况。这种方法最棒的地方是,顶部节点将保持"增长"(存储更大的间隔(,并与其继任者或前任合并,因此树在内存使用方面实际上会收缩,最终每次操作的时间衰减为O(1(。你也不会浪费任何数字,所以你可以一直生成,直到你有2^64个数字。
该算法具有O(N lg N)
初始化、O(1)
查询和O(N)
内存使用。我假设你有一些整数类型,我将其称为int64
,它可以表示整数[0, int64_max]
。
- 对数字排序
- 创建包含间隔
[u, v]
的链接列表 - 插入
[1, first number - 1]
- 对于剩余的每个数字,插入
[prev number + 1, current number - 1]
- 插入
[last number + 1, int64_max]
现在,您有一个表示未使用的数字的列表。您可以简单地对它们进行迭代以生成新的数字。
我认为应该使用某种哈希。所以你可以根据MOD操作将你的卡存储在一些桶中。在创建某种索引之前,你会被整个数组的循环所困扰。
如果您了解一下java中的HashSet实现,您可能会得到一些线索。
编辑:我想你希望它们是随机数,如果你不介意下面的序列MAX+1是一个好的解决方案:(
您可以构建一个现有元素的二进制树,并遍历它,直到找到一个深度不为64且子节点少于两个的节点。然后,您可以构造一个"丢失"的子节点并拥有一个新元素。如果我没有弄错的话,应该相当快,大约在O(n(的顺序。
bool seen[1001] = { false };
for each element of the original array
if the element is in the range 0..1000
seen[element] = true
find the index for the first false value in seen
初始化:不要对列表进行排序。创建一个1000长的包含0..999的新数组。对列表进行迭代,如果任何数字在0..999范围内,则将新数组中的值替换为列表中第一项的值,使其在新数组中无效。
插入:对新数组使用递增索引。如果此索引处的新数组中的值不是列表中第一个元素的值,请将其添加到列表中,否则请检查新数组中下一个位置的值。当新数组用完时,使用1000.1999重新填充,并如上所述使现有值无效。是的,这是在列表上循环,但不必每次插入都这样做。
接近O(1(,直到列表变得如此之大,以至于偶尔迭代它以使"新"新数组无效变得非常重要。也许你可以通过使用一个不断增长的新数组来缓解这种情况,也许蜜蜂总是列表的大小?
Rgds,Martin
将它们全部放入一个大于1000的哈希表中,并找到空单元格(这是停车问题(。为此生成密钥。当然,对于更大的桌子来说,这会更好。该表只需要1位条目。
编辑:这就是鸽子洞原理。这需要哈希函数的"模表大小"(或其他"半可逆"函数(。
unsigned hashtab[1001] = {0,};
unsigned long long long long numbers[1000] = { ... };
void init (void)
{
unsigned idx;
for (idx=0; idx < 1000; idx++) {
hashtab [ numbers[idx] % 1001 ] += 1; }
}
unsigned long long long long generate(void)
{
unsigned idx;
for (idx = 0; idx < 1001; idx++) {
if ( !hashtab [ idx] ) break; }
return idx + rand() * 1001;
}
基于这里的解决方案:关于数组和数字的问题
由于有1000个数字,如果我们考虑它们的余数为1001,那么至少会缺少一个余数。我们可以选择它作为我们丢失的号码。
因此,我们保持一个计数数组:C[1001],它将保持C[r]中余数r(除以1001(的整数的数量。
我们还维护了一组C[j]为0的数字(比如使用链表(。
当我们移动窗口时,我们递减第一个元素的计数(比如余数i(,即递减C[i]。如果C[i]变为零,我们将i加到这组数字上。我们用添加的新数字更新C数组。
如果我们需要一个数字,我们只需从C[j]为0的j集合中选择一个随机元素。
对于新数字,这是O(1(,最初是O(n(。
这与其他解决方案类似,但并不完全相同。
像这样简单的东西怎么样:
1( 将数组划分为1000以下和以上的数字
2( 如果所有的数字都在下分区内,那么选择1001(或任何大于1000的数字(,我们就完成了。
3( 否则,我们知道一定存在一个在1到1000之间的数字,而这个数字在下分区中不存在。
4( 创建一个由bools组成的1000元素数组,或一个1000元素长的位字段,或诸如此类的东西,并将数组初始化为所有0的
5( 对于下分区中的每个整数,使用其值作为数组/位字段的索引,并将相应的布尔设置为true(即:进行基数排序(
6( 遍历数组/位字段并选择任何未设置值的索引作为解决方案
这在O(n(时间内有效,或者因为我们将所有事物都限制在1000以内,所以从技术上讲,它是O(1(,但一般来说是O(n(时间和空间。数据有三次传递,这不一定是最优雅的方法,但复杂性仍然是O(n(。
您可以用原始数组中没有的数字创建一个新数组,然后从这个新数组中选择一个。
?O(1(?
- 给定n个元素的m个集合.在C++中找到出现在最大集合数中的元素
- 基于多个条件处理地图中的所有元素
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 如何在C++中写入 1000 个文件时有效地缓冲
- 如何计算大小为 1000 x 1000 的 2D 数组中 2 个元素之间的步幅?C++
- 如何在没有同步的情况下使用多个线程(2、4,8、16 个线程)在循环(10,100、1000 个周期)中打印字符串?
- C# 选项,以最好地使用具有 1000 个函数的 C++ DLL
- QTableView 在 1000 个可见单元格下性能缓慢
- 初始化 1000 个地图元素
- 字符串输入超过1000个字符时执行挂起
- 如何在不阻塞UI的情况下在QGraphicsScene中移动1000个项目
- 如何输入包含少于1000个单词的带有空格和标点符号的文本
- 找出给定长度为100的字符串中的1000个的最小唯一子字符串的长度
- 如何使用 if 检查字符串数组的第一个元素第一个符号?
- 如何缓存1000个大型C++对象
- 编写程序生成1000个0-49范围内的随机整数.(c++)
- Pthreads池,保持1000个打开线程,pthread_create()返回11
- 生成一个不同于数组中1000个元素的新元素
- 将文件的前1000个字符读入缓冲区,将换行符转换为 ,并将字符串的地址位置存储为char*[]
- 对1000个整数的数组进行排序