编辑: 我忘了提到我不想分配另一个临时数组。
我正在尝试解决C语言中的一个问题: 假设给定一个数组a,其大小为N。您知道该数组中的所有元素都在0到n-1之间。如果在(0到n-1)范围内缺少数字,则该函数应返回0。否则,它将返回1。如您所知,可以重复。问题是它应该在O(n)运行时上运行。 我想我设法做到了,但我不确定。从这里的旧文章来看,似乎几乎是不可能的,而且算法似乎比我拥有的算法复杂得多。因此,我感到有些不对劲。 我找不到您返回错误输出的输入。
无论如何,我们将不胜感激您的反馈,或者,如果您能想到可能不起作用的输入,这是代码:
int missingVal(int* a, int size)
{
int i, zero = 0;
for (i = 0; i < size; i++)
//We multiply the element of corresponding index by -1
a[abs(a[i])] *= -1;
for (i = 0; i < size; i++)
{
//If the element inside the corresponding index is positive it means it never got multiplied by -1
//hence doesn't exist in the array
if (a[i] > 0)
return 0;
//to handle the cases for zeros, we will count them
if (a[i] == 0)
zero++;
}
if (zero != 1)
return 0;
return 1;
}
答案 0 :(得分:2)
您的程序可以工作并且位于O(N)中,但是它很复杂,最糟糕的是它会修改初始数组
可以就是这样:
int check(int* a, int size)
{
int * b = calloc(size, sizeof(int));
int i;
for (i = 0; i != size; ++i) {
b[a[i]] = 1;
}
for (i = 0; i != size; ++i) {
if (b[i] == 0) {
free(b);
return 0;
}
}
free(b);
return 1;
}
答案 1 :(得分:2)
只需将值复制到另一个数组即可,将每个值放在其顺序位置。然后浏览副本以查看是否缺少任何内容。
答案 2 :(得分:2)
这个问题与相同一样,无法确定您的阵列是否重复。这就是为什么
0
和n-1
之间n
如果该范围内缺少数字,则仅表示另一个数字代替了它。这意味着数组必须有重复的数字
int missingVal(int arr[], int size)
{
// Increment all the numbers to avoid an array with only 0s
for (int i = 0; i < size; i++) arr[i]++;
for (int i = 0; i < size; i++)
{
if (arr[abs(arr[i])] >= 0)
arr[abs(arr[i])] = -arr[abs(arr[i])];
else
return 0;
}
return 1;
}
如Bruno所述,如果我们有一个全为零的数组,那么我们可能会遇到问题。这就是为什么我在所有 edit 中增加所有数字的原因。
虽然这在算法中又添加了一个“ pass”,但解决方案仍然是 O(n)时间和O(1)空间
Bruno另一个优化此建议的好建议是,查看是否存在多个零而不是递增数组。
如果有2个或更多,我们可以直接返回0
,因为我们发现了一个重复项(并且由于相同的原因,并不是该范围内的所有数字都在数组中)
答案 3 :(得分:0)
为克服排除任何额外内存消耗的要求,发布的算法只需简单地取反数组的值即可更改数组中的值,但这将使索引0保持不变。
我提出了一个不同的映射:从[0,size)到( -1-size , -1 ],这样例如{0,1,2, 3,4,...}变为{-1,-2,-3,-4,-5,...}。请注意,对于整数的二进制补码表示,INT_MIN = -INT_MAX-1。>
// The following assumes that every value inside the array is in [0, size-1)
int missingVal(int* a, int size) // OT: I find the name misleading
{
int i = 0;
for (; i < size; i++)
{
int *pos = a[i] < 0
? a + (-a[i] - 1) // A value can already have been changed...
: a + a[i];
if ( *pos < 0 ) // but if the pointed one is negative, there's a duplicate
break;
*pos = -1 - *pos;
}
return i == size; // Returns 1 if there are no duplicates
}
如果需要,可以在返回之前通过一个简单的循环恢复原始值
if ( i != size ) {
for (int j = 0; j < size; ++j) {
if ( a[j] < 0 )
a[j] = -a[j] - 1;
}
} else { // I already know that ALL the values are changed
for (int j = 0; j < size; ++j)
a[j] = -a[j] - 1;
}