关于找到两个元素的数组之间的最小差异的困惑

时间:2012-05-23 19:31:43

标签: c optimization

我发现了Find the minimum difference between two arrays的帖子 并且使用我试图解决SPOJ问题的概念 - http://www.spoj.pl/problems/ACPC11B但奇怪的是我得到了WA(错误答案)!!!!

然后我尝试了简单的方法..
使用两个for循环..
计算每个元素之间的差异...
然后我得到了AC。 !!!!

任何人都可以告诉我为什么这个方法
if(| A [i + 1] - B [j] |< | A [i] - B [j + 1] |)然后递增i,否则增量j在这种情况下失败????

编辑:我忘了提到当我实现第一种方法时,我已经在两个阵列上执行了qsort ...
同样在SPOJ问题中,不需要差异最小的元素的索引。只需要最小的差异!!!

3 个答案:

答案 0 :(得分:2)

第一个链接中的方法仅在两个数组都已排序时才有效。 SPOJ问题涉及未排序的数组。这就是该方法不起作用的原因。如果对数组进行排序,则可以应用第一种方法,但是您需要跟踪原始索引(即排序前每个值的位置)。通过将每个值转换为(值,索引)对然后对这些对进行排序,这是可行的。这样你将有一个O(m log m + n log n)解决方案,而不是你的强力(但正确)O(mn)解决方案(其中m和n是数组长度)。

编辑根据您发布的代码,我有不同的答案。您的循环条件错误。例如,如果i == (x - 1)只有j != (y - 1),则循环将执行,您将a[x]b[j]进行比较。这是a的非法下标。此外,这应该是读取SPOJ中描述的相同输入吗?我不知道你在哪里读取测试用例的数量。

答案 1 :(得分:0)

您无法比较数组的第一个元素。也就是说,如果最小差异是| a[0]-b[0] |并且在任何其他元素对之间不会出现这种差异,因为您的比较以| a[1]-b[0] |开头,所以您将无法找到它和| a[0]-b[1] |。

答案 2 :(得分:0)

这是我认为应该做的伎俩(基于你的代码),基本上你的代码没有检查2个案例:

首先,当最小值介于数组中的2个第一个值之间时。

其次是我们检查了一个数组中的每个值,但仍然在第二个数组中有值。 (考虑案例a [0,1,2],b [-1,-2,-3,-5,-6,2])

#include <stdlib.h>
#include <stdio.h>
#include <time.h>


int comp(const void * a,const void * b)
{
    if (*(int*)a==*(int*)b)
        return 0;
    else if (*(int*)a < *(int*)b)
        return -1;
    else
        return 1;
}

int main()
{
    int x,y;
    printf("x: ");
    scanf ("%d", &x);
    int a[x];
    srand(time(NULL));
    for (int i = 0; i < x; i++)
    {
        a[i] = rand() % 30 - 15;
        //scanf ("%d", &a[i]);
        printf ("%d\n",a[i]);
    }

    printf("y: ");
    scanf ("%d", &y);

    int b[y];
    for (int i = 0; i < y; i++)
    {
        b[i] = rand() % 30 - 15;
        //scanf ("%d", &b[i]);
        printf ("%d\n",b[i]);
    }


    qsort(a,x,sizeof(int),comp) ;
    qsort(b,y,sizeof(int),comp) ;
    int i = 0, j = 0;
    int * inc; // using a pointer to select which var to increment. Avoid repeating code, optional and subjective approach.
    int minimum = abs(a[0]-b[0]); // Set min to be a[0] - b[0] which is never checked in the loop

    /* Added the min > 0 condition to avoid looping unnecessarily and avoid the break statement
    Changed the condition from && to || in order to handle the second case
    Changed the != to < which is more restrictive */
    while (minimum > 0 && (i < (x - 1) || j < (y - 1)))
    {

        int z;
        if ( i == x-1) // we've reached the end of a, inc j automatically
        {
            inc = &j;
            z = abs(a[i]-b[j+1]);
        }
        else if ( j == y -1 ) // we've reached the end of b, inc i automatically
        {
            inc = &i;
            z = abs(a[i+1]-b[j]);
        }
        else // here's the original loop, rewritten to shorten the code
        {
            int zi = abs(a[i+1]-b[j]);
            int zj = abs(a[i]-b[j+1]);
            if ( zi < zj)
            {
                inc = &i;
                z = zi;
            }
            else
            {
                inc = &j;
                z = zj;
            }
        }
        if ( z < minimum)
        {
            minimum = z;
        }

        (*inc)++;
    }
    printf("min: ");
    printf ("%d\n", minimum);
    return 0;

}