有效地找到一个不在40、400或4000尺寸的整数
Efficiently find an integer not in a set of size 40, 400, or 4000
与经典问题有关的
在给定的四十亿个,但不是完全相同的整数。
通过 Integers 我真正的意思只是其数学定义的一个子集。也就是说,假设只有有限数量的整数。在C 中说,它们是[INT_MIN, INT_MAX]
的int
。
现在给出了std::vector<int>
(无重复)或std::unordered_set<int>
,其大小可以为40、400、4000左右,但不太大,如何有效地生成一个不在给定的数字?
如果不担心溢出,那么我可以将所有非零的产品乘以1。但是有。对手测试用例可能删除了INT_MAX
。
我更支持简单的非随机方法。有什么吗?
谢谢!
更新:要清除歧义,假设一个未分类的std::vector<int>
保证没有重复。因此,我问是否有比O(n log(n))更好的东西。另请注意,测试用例可能同时包含INT_MIN
和INT_MAX
。输入。最简单的候选人是0
到N
的数字。这需要O(N)
空间和时间。
int find_not_contained(container<int> const&data)
{
const int N=data.size();
std::vector<char> known(N+1, 0); // one more candidates than data
for(int i=0; i< N; ++i)
if(data[i]>=0 && data[i]<=N)
known[data[i]]=1;
for(int i=0; i<=N; ++i)
if(!known[i])
return i;
assert(false); // should never be reached.
}
随机方法可以更有效地有效,但在最坏情况下可能需要更多通过数据。
随机方法确实非常有效。
如果我们想使用确定性方法并假设大小 n 不太大,例如4000,那么我们可以创建一个大小 m = n + 1
的vector x (或稍大一点,例如4096,以促进计算),以0。
对于范围内的每个i
,我们只是设置x [array [i] modulo m] =1。
然后,在 x 中的简单O(n)搜索将提供一个不在 array中的值
注意:Modulo操作不完全是"%"操作
编辑:我提到通过在此处选择4096的大小使计算变得更容易。要更具体,这意味着使用简单的&
操作执行Modulo操作
如果允许使用以下算法重新排序输入向量,则可以使用O(1)辅助空间在O(n)时间中找到最小的未使用整数。[注1](如果向量包含重复的数据,则该算法也有效。)
size_t smallest_unused(std::vector<unsigned>& data) {
size_t N = data.size(), scan = 0;
while (scan < N) {
auto other = data[scan];
if (other < scan && data[other] != other) {
data[scan] = data[other];
data[other] = other;
}
else
++scan;
}
for (scan = 0; scan < N && data[scan] == scan; ++scan) { }
return scan;
}
第一份通过保证,如果在k
之后找到[0, N)
中的某些k
,则现在位于位置k
。该重排是通过交换来完成的,以避免丢失数据。扫描完成后,第一个条目的值与数组中任何地方都没有引用其索引。
断言可能不是100%明显的,因为可以从较早的索引中引用条目。但是,在这种情况下,该条目不可能是其索引的第一个条目,因为较早的条目将符合该标准。
要看到该算法是O(n),应观察到只有在目标条目不等于其索引时,第6和7行的交换才能发生,并且交换后目标条目等于索引。因此,大多数N
互换都可以执行,并且第5行的if
条件最多为true
,最多为N
次。另一方面,如果if
条件为false,则scan
会增加,这也只能发生N
次。因此,if
语句最多是2N
次(是O(n))。
注意:
- 我在这里使用了未签名的整数,因为它使代码更清晰。可以轻松地针对已签名的整数调整算法,例如,通过将
[INT_MIN, 0)
签名的整数映射到未签名的整数[INT_MAX, INT_MAX - INT_MIN)
(减法是数学的,而不是根据C语义,而不是根据C语义的表示。那是相同的位模式。当然,这会改变数字的顺序,这会影响"最小未使用整数"的语义;也可以使用保留订单的映射。
制作随机x(int_min..int_max)并对其进行测试。测试X 故障(40/400/4000的非常罕见的情况)。
步骤1: 对vector 。
排序可以在O(n log(n))中完成的,您可以在线找到一些不同的算法,使用最喜欢的算法。
步骤2:在vector 中找到第一个int 。
轻松从int_min到int_min 40/400/4000检查向量是否具有当前INT:
伪代码:
SIZE = 40|400|4000 // The one you are using
for (int i = 0; i < SIZE; i++) {
if (array[i] != INT_MIN + i)
return INT_MIN + i;
解决方案将为 o(n log(n) n)含义: o(n log(n))
编辑:只需阅读您的编辑,要求比 o(n log(n))更好的东西(n log(n)),对不起。
对于在std::unordered_set<int>
中提供整数的情况(与std::vector<int>
相对),您可以简单地遍历整数值的范围unordered_set<int>
中不存在的整数值。在std::unordered_set<int>
中搜索整数的存在非常简单,因为std::unodered_set
确实通过其find()
成员函数提供了搜索。
这种方法的空间复杂性将为 o(1)。
如果您开始以最低的 int
可能值(即std::numeric_limits<int>::min()
)的可能值,则您将获得std::unordered_set<int>
中未包含的最低最低 int
:
int find_lowest_not_contained(const std::unordered_set<int>& set) {
for (auto i = std::numeric_limits<int>::min(); ; ++i) {
auto it = set.find(i); // search in set
if (it == set.end()) // integer not in set?
return *it;
}
}
类似地,如果您开始以最大的 int
的可能值(即std::numeric_limits<int>::max()
),则将获得std::unordered_set<int>
中不包含的最低 int
:最低> CC_43:
int find_greatest_not_contained(const std::unordered_set<int>& set) {
for (auto i = std::numeric_limits<int>::max(); ; --i) {
auto it = set.find(i); // search in set
if (it == set.end()) // integer not in set?
return *it;
}
}
假设int
s是由哈希函数统一在unordered_set<int>
的桶中映射的,则可以在恒定时间内实现unordered_set<int>
上的搜索操作。然后,运行时复杂性将为 o(m),其中 m 是您正在寻找非邻近值的整数范围的大小。 m 由unordered_set<int>
的大小上限(即,在您的情况下 m&lt; = 4000 )。
的确,使用这种方法,选择大小大于unordered_set
大小的任何整数范围,可以保证会出现与unordered_set<int>
中不存在的整数值。
- 如何反转整数参数包
- enum是C++中的宏变量还是整数变量
- 努力将整数转换为链表。不知道我在这里做错了什么
- 整数不会重复超过随机数
- 在C++中手动调整数组大小
- 检查输入是否不是整数或数字
- C++使用整数的压缩数组初始化对象
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 如何只允许用户输入正整数
- 如何在c++中从文本文件中逐行读取整数
- C++:如何循环通过向量中的整数元素
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 序列化,没有库的整数,得到奇怪的结果
- 在一定长度后从数组中打印时缺少整数
- std::当在256字节边界上写入整数时,流的奇怪行为
- 内联程序集printf将整数解释为地址
- 是否基于数组B整数打印数组A中的整数
- 有效地找到一个不在40、400或4000尺寸的整数