使用了O发现的范围内的元件(n)的运行时

问题描述 投票:4回答:3

我试图写入接收具有大小“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)。

c
3个回答
4
投票

如果你允许修改输入数组,这个问题可以在O(N)来解决。

观察:

  1. 如果阵列排序,这个问题将是微不足道的。
  2. 对数组排序0 ... N-1,其中值也是0 ... N-1也是微不足道的,因为每个元件的位置是其值,可以重复一次,交换元件到其最终位置。

只是交换,在位置的元素我已经没有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}


3
投票

这是我的版本。它运行在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)));
}

2
投票

所有的值都是正的,所以我们可以利用我们的目的位标志。

迭代这个数组;对于每一个元素,检查它是否是负的,如果是否定,并减去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;
} 
© www.soinside.com 2019 - 2024. All rights reserved.