面试难题:数组大小-n包含来自[i,i + n)的数字

时间:2011-03-24 18:05:30

标签: c algorithm puzzle

给定一个未排序的数字数组,编写一个函数,如果数组由连续的数字组成,则返回true。

示例:

  1. 如果数组为{5,2,3,1,4},则该函数应返回true,因为该数组具有从1到5的连续数字。

  2. 如果数组为{83,78,80,81,79,82},则该函数应返回true,因为该数组具有从78到83的连续数字。

  3. 如果数组为{34,23,52,12,3},则该函数应返回false,因为元素不是连续的。

  4. 如果数组为{7,6,5,5,3,4},则该函数应返回false,因为5和5不连续。

  5. 我提出了以下算法:

    1. 找到数组的最大值和最小值

    2. max-min + 1应该是数组的大小

    3. 检查重复项

    4. 检查

    5. 之间的所有连续数字

      如何实现第4条路径?(复杂性应为O(n)

      非常欢迎其他建议。

8 个答案:

答案 0 :(得分:18)

如果输入数组是A:

  1. 查找A的最小值和最大值,如果数组的大小错误,则返回False。

  2. 创建一个大小相同的新数组B,最初全部为零

  3. 对于每个索引i,让B [A [i] - min] = 1。

  4. 检查B是否仍然包含任何零。

  5. 每一步都需要O(n)时间。

答案 1 :(得分:2)

bool consecutive(int a[], size_t n)
{
    int min = find_min(a,n);
    int max = find_max(a,n);

    if (max - min + 1 == n) {
        // variant of counting sort, O(n)
        // note: never freed, don't use in production
        int *freq = calloc(sizeof(int), n);

        for (size_t i=0; i<n; i++)
            if (++freq[a[i] - min] > 1)
                return false;
        return true;
    }
    return false;
}

答案 2 :(得分:2)

int visited[max - min + 1];

for(c = min; c <= max; c++) {
    visited[array[c] - min] += 1;

    if(visited[array] > 1)
        return false;               // since this is a duplicate
}

这应该没问题。 visited []跟踪原始数组中出现的数字的次数。如果它的任何元素大于2,那么就有重复,所以返回false; 由于两个数组的大小都是max-min + 1,所以在循环结束时[]已经满了,因为我们访问了array []的所有元素。所以它访问是空的,某处必须有重复,但我们不需要打扰,因为那时我们仍然返回false。

答案 3 :(得分:2)

在我看来,这可以在O(n)时间内用O(1)额外的空间来完成。

确定数组的最小值和最大值。如果(max - min + 1)!= n,则返回false。

从数组中的每个元素减去min。我们现在有一个数组,其中包含范围为[0,n)的n个元素。我们现在只需检查重复项。这可以通过以下代码在线性时间内完成(每个元素最多移动一次):

for (int i = 0; i != n; ++i)
{
    if (A[i] != i)
    {
        int temp = A[i];
        for (;;)
        {
            int index = temp;
            if (A[index] == index)
            {
                // We have a duplicate
                return false;
            }
            std::swap(temp, A[index]);
            if (index == i)
            {
                // A[i] now contains i
                break;
            }
        }
    }
}
// If we get to here, there are no duplicates

答案 4 :(得分:0)

我不太擅长C,但你需要做第4步吗?当然如果2是真的并且没有重复,则它包含序列,否则它不包含?

答案 5 :(得分:0)

根据你的要求,你的算法的第四步根本不需要(因为#2和#3将保证它们是连续的)

我们可以通过一次遍历中的所有步骤来保存算法的更多比较(以提高其时间复杂度):

int is_consecutive(int *a, int size)  // O(n) algo
{   
 int min, max;
 hash H;
 if(!a || size == 0 ) return -1;
 max=min=a[0];
 H.insert(a[0]);

 for(i=1; i<size; i++) {
   if(H.find(a[i]) { delete H; return 0; }  // duplicacy check
   else H.insert(a[i]);
   if(a[i] < min) min = a[i];
   else if(a[i] > max) max = a[i];
 }
 if(size != (max - min)) { delete H; return 0; }  //range = size check
 delete H;   
 return 1;
}

答案 6 :(得分:-2)

这是适用于1..N的东西,你可以使用算术系列公式来调整[i,i + n]

// gcc -Wall q1.cc -o q1 && q1                                                                          

//Given an array of size N in which every number is between 1 and N, write a simple program to determine
//if there are any duplicates in it.                                                                    

//answer                                                                                                
/* The numbers can be assumed to not be stored in sorted order.  We also assume that all numbers are    
between 1 and N inclusive.  If for example they are not, then we will return true indicating that there 
is a possibility of a duplicate.                                                                        

This can be implemented using a bit array of size N all initialized to 0.  as we iterate the input array
of numbers, we simply check if the bit array at that number index is set, if so, we return true.  if not
we set the bit.  we loop until we get to the end of the list, and if we get there, that means no        
duplicate was found, and we can return false.                                                           

However, the above algorithm has the problem of using extra space.  A better idea is to take advantage  
of the fact that we are guaranteed that the numbers are between 1 and N.  if we were to use the fact    
that the arithmetic sum of these numbers is equal to n(n+1)/2, then we can just sum up all the numbers  
and ensure that it equals the above sum.  If it does, we have no duplicate, else we do.                 
*/                                                                                                      

#include <stdio.h>                                                                                      
#include <assert.h>                                                                                     

bool any_dup(const int *a, int n)                                                                       
{                                                                                                       
        int req_sum = n*(n+1)/2;                                                                        

        int s = 0;                                                                                      
        for (int i = 0;i<n;i++)                                                                         
                s += a[i];                                                                              

        return (s != req_sum);                                                                          
}                                                                                                       


int main()                                                                                              
{                                                                                                       
        int a[]={1,2,3,4,5};                                                                            
        assert(!any_dup(a,5));                                                                          

        int b[]={1,2,2,3,3,4,5,6};                                                                      
        assert(any_dup(b,8));                                                                           

        int c[]={5,2,3,1,4};                                                                            
        assert(!any_dup(c,5));                                                                          

        int d[]={34,21,1,4,2};                                                                          
        assert(any_dup(d,5));                                                                           

        return 0;                                                                                       
}                                                                                                       

答案 7 :(得分:-2)

查找数组中的min元素,Max元素和元素总和。

它们形成一个Arthematic Progression,元素之和为:( no.Of element / 2)*(2 * minElement +(n-1)* differencence)

在这种情况下差异为1

如果sum ==(array.length / 2)*(2 * minElement +(array.length-1)* 1)&amp;&amp; maxElement ==(minElement +(lenght ofArray-1)* 1)

然后数字是连续的。

没有额外的空间复杂性,时间复杂度为O(n)

感谢@jpalecek进行纠正。现在应该没问题