int
,因为每个int是一组位。此外,需要考虑到我已经有一个包含1000张这样的卡片的数组。我必须每次生成一个新元素,该元素与之前的1000张卡片不同。数组中的整数(也称为卡片)不一定按顺序排列。
更重要的是,如果问题是针对C++的,那么
64位int
从哪里来,以及如何从数组中生成这张新卡片,使其与数组中已有的所有元素都不同呢?int
,因为每个int是一组位。64位int
从哪里来,以及如何从数组中生成这张新卡片,使其与数组中已有的所有元素都不同呢?有2的64次方个64位整数,这个数字比1000还大得多,最简单的解决方法是生成一个随机的64位数字,并验证它是否在已生成数字的表中(即使它出现的概率非常小,但你最好确定一下)。
由于大部分随机数生成器不会生成64位值,因此你只能编写自己的随机数生成器,或者(更简单的方法)将值合并,例如通过生成8个随机字节,然后将它们memcpy
到一个uint64_t
中。
至于验证数字是否已经存在,对于一个或两个新数字来说,std::find
就足够了;如果你需要查找很多数字,那么对表进行排序并使用二分查找会很值得。或者使用某种类型的哈希表。
std::find
一样,所以在这两种情况下生成的时间都是 O(n)。 - Fred Foomap
中插入元素需要进行分配,这可能会对常数因子产生非常大的影响。(当然,如果性能真的成为问题,还有更好的解决方案可用。但它们更加复杂,因此更容易出错。) - James Kanze我可能有所遗漏,但是其他大部分答案对我来说过于复杂。只需对原始数组进行排序,然后从零开始计数:如果当前计数在数组中,则跳过它,否则你就得到了下一个数字。这个算法的时间复杂度为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;
}
}
}
bool IsGreatFive(const char*) {return true;}
。 - Mooing Duck这里有一个时间复杂度为O(n)的算法:
int64 generateNewValue(list_of_cards)
{
return find_max(list_of_cards)+1;
}
注意:正如@amit在下面指出的那样,如果INT64_MAX
已经在列表中,这个方法将会失败。
就我所知,这是你唯一可以得到O(n)时间复杂度的方法。如果你想要处理这个(相当重要的)边缘情况,那么你必须进行一些适当的排序或搜索,这将使你的时间复杂度达到O(n log n)。
list_of_cards.append(generateNewValue(list_of_cards))
。 - Oliver CharlesworthUINT64_MIN
或者 j = UINT64_MAX
,否则 i-1 和 j+1 都是新键的有效候选项。如果两个都为真,则已经存储了 2^64 个元素,无法生成新元素。存储新元素,最坏情况下需要 O(lg n) 的时间。O(N lg N)
,查询时间复杂度为O(1)
,内存使用量为O(N)
。我假设您有一些整数类型,我将其称为int64
,它可以表示整数[0,int64_max]
。
[u,v]
的链表[1,第一个数字-1]
[上一个数字+1,当前数字-1]
[最后一个数字+1,int64_max]
现在您拥有一个代表未使用的数字的列表。您可以简单地迭代它们以生成新数字。
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
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;
}
我认为使用某种哈希方式是可行的。因此,您可以根据MOD操作将卡片存储在一些桶中。除非您创建某种索引,否则只能循环整个数组。
如果您查看Java中HashSet的实现,您可能会得到一些线索。
编辑:我假设您希望它们是随机数,如果您不介意序列MAX+1,则以下是一个好的解决方案 :)
初始化: 不要对列表进行排序。 创建一个新的长度为1000的数组,包含0..999。 遍历列表,如果任何数字在0..999范围内,则通过将新数组中的值替换为列表中第一项的值来使其无效。
插入: 使用递增索引到新数组。如果该索引处的新数组中的值不是列表中的第一个元素的值,则将其添加到列表中,否则检查新数组中下一个位置的值。 当新数组用完时,使用1000..1999重新填充它,并像上面那样使现有值无效。是的,这是在列表上循环,但不必为每个插入执行此操作。
近似O(1),直到列表变得非常大,以至于偶尔迭代它以使“新”新数组无效变得显着。也许您可以通过使用一个增长的新数组来缓解这种情况,可能始终是列表的大小?
敬礼, 马丁