我试图写入接收具有大小“N”的阵列来自用户的功能,具有之间的值0 ---> N-1的函数应该返回“1”,如果所有0之间的值---->Ñ -1在那里否则返回0,我们可以假设数字,用户将输入才有效值。之间0 ----> N-1。
例如:N = 5,值:2,1,4,0,3 ---->返回1,N = 5,值:2,3,4,0,3 ---->返回0
我想尽各种办法来解决这个问题。
想过一个因子,但发现有很多方法可以让使用重复的号码和唯一编号相同的阶乘。也想过总和的数字,但仍然太多的方法可以得到同样的答案。有没有什么办法,以确保我只有无子阵独特的项目?
WE不能使用子阵列(另一计数器阵列等),并且函数应该运行为O(n)。
如果你允许修改输入数组,这个问题可以在O(N)来解决。
观察:
只是交换,在位置的元素我已经没有i的值,这意味着我在数组中出现两次过程中需要额外的检查。
int check(unsigned* a, unsigned size) {
for (unsigned i = 0; i < size; ++i) {
unsigned b = a[i];
if (b != i) {
do {
if (b < 0 || b >= size)
return false; // value out of range
unsigned c = a[b];
if (b == c)
return false; // duplicate value
a[b] = b;
b = c;
} while (b != i);
a[i] = i;
}
}
return true;
}
需要注意的是内循环,使解决方案看起来O(N2),但它不是 - 每个元素都被访问最多的两倍。是需要的内循环,以解决循环如在{1,2,3,0}
。
这是我的版本。它运行在O(N)。
我们的想法是操纵原始数组,并以纪念已遇到的所有值增加N到它。然后我们做了扫描和检查所有值都大于或大于N等于和值更改回原来的一个。
唯一要注意的是,阵列必须是可变的。
#include <stdio.h>
int check(unsigned* a, size_t size) {
for (size_t i = 0; i < size; ++i) {
if (a[i] >= size) {
return 0;
}
}
for (size_t i = 0; i < size; ++i) {
size_t const x = a[i] % size;
a[x] = x + size;
}
int result = 1;
for (size_t i = 0; i < size; ++i) {
if (a[i] < size) {
result = 0;
} else {
a[i] = a[i] - size;
}
}
return result;
}
int main() {
unsigned a1[] = {0,5,1,3,2,4};
unsigned a2[] = {0,5,1,3,0,0};
printf("a1: %d\n",check(a1,sizeof(a1)/sizeof(*a1)));
printf("a2: %d\n",check(a2,sizeof(a2)/sizeof(*a2)));
}
所有的值都是正的,所以我们可以利用我们的目的位标志。
迭代这个数组;对于每一个元素,检查它是否是负的,如果是否定,并减去1.如果是超出有效范围[0,N-1]当然,输入数组是无效的,但你说我们不担心这个。
如果它在的范围内,用它作为数组本身中的索引;如果您发现该值为正使它负,减1,如果是负值,这意味着有重复的元素(你已经签署交换的话)。
(以下简称“减去1”的事情是占0,否定时保持相同)
由于鸽巢原理,如果到达最后一个元件没有重复,没有出范围,输入数组包含所有,只在范围[0,N-1]的元素。如果你觉得不好离开阵列的所有负面的,你可以做一个最后一关翻转每个数字的符号。
bool check(int *arr, int N) {
bool ret = true;
for(int i = 0; i < N && ret; ++i) {
int v = arr[i];
if(v < 0) v = -v - 1;
if(v >= N || arr[v] < 0) ret = false;
else arr[v] = -arr[v] - 1;
}
for(int i = 0; i < N; ++i) {
if(arr[i] < 0) arr[i] = -arr[i] - 1;
}
return ret;
}