【问题标题】:Comparing between a number and array比较数字和数组
【发布时间】:2022-01-01 13:46:28
【问题描述】:

我正在尝试将一个数字与包含某些未知值的数组进行比较,并且我想获得小于比较数字的整数个数。

例如:

数组将是:-2 5 2 5 7 9 10

比较号码是:8

回答:5

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

long long data[200000] = { 0 };

int cmpfunc(const void *a, const void *b) {
    return (*(long long*)b - *(long long*)a);
}

int main() {
    int numbers, i, j, z, counter, testcases;
    long long check;
    scanf("%d", &numbers);
    for (i = 0; i < numbers; i++)
        scanf("%lld", &data[i]);

    qsort(data, numbers, sizeof(long long), cmpfunc);

    scanf("%d", &testcases);
    for (j = 0; j < testcases; j++) {
        scanf("%lld", &check);
        counter = numbers;
        
        for (z = 0; z < numbers; z++) {
            if (check >= data[z])
                break;
            counter--;
        }
        printf("%d\n", counter);
    }
}

我的程序运行速度仍然比要求的慢,有什么办法可以加快速度吗?

【问题讨论】:

  • 你可以看看 binary search
  • 如果你有一个排序数组,那么,你可以使用具有 O(logn) 时间复杂度的二分查找。但是,您可以在不对数组进行排序的情况下进行线性搜索。因为,排序数组具有 O(nlogn) 时间复杂度。这就是您的算法具有 O(nlogn) 时间复杂度的原因。但是,您可以通过线性搜索以 O(n) 的时间复杂度完成您的任务。
  • 为什么要使用long long
  • 示例数据集很小。 “真实”数据集能有多大?请注意,标准的二进制搜索无济于事;在样本数据中,它会寻找 8 却找不到它。你需要一个修改过的二分查找,找到小于目标值的最大值的位置。

标签: c


【解决方案1】:

您的方法存在一些问题:

  • 如果两个数字的差值超出int类型的范围,则比较功能无法正常工作,即使int的值也很容易实现,例如:比较INT_MAXINT_MIN。你应该改用这个:

      int cmpfunc(const void *aa, const void *bb) {
          const long long *a = aa;
          const long long *b = bb;
          return (*a > *b) - (*a < *b);
      }
    
  • 对值进行排序对于您的目标而言并非总是必要的:仅当查找次数大于 log2(N) 时才有用,因为对数组进行排序所花费的时间与 N.log(N) 成正比.

  • 此外,您应该利用排序,使用二进制搜索来定位数字潜在位置并直接从该位置确定计数。当前使用线性搜索的方法对已排序和未排序数组的工作方式相同。

  • 除非它是作业的一部分,否则 200000 可能不足以满足所有测试用例。分配数组似乎是更好的方法。

这是修改后的版本:

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

int cmpfunc(const void *aa, const void *bb) {
    const long long *a = aa;
    const long long *b = bb;
    return (*a > *b) - (*a < *b);
}

int main() {
    int numbers, i, j, z, counter, testcases;
    long long *data;
    long long check;

    if (scanf("%d", &numbers) != 1)
        return 1;
    data = calloc(sizeof(*data), numbers);
    if (!data)
        return 1;
    for (i = 0; i < numbers; i++) {
        if (scanf("%lld", &data[i]) != 1)
            return 1;
    }
    if (scanf("%d", &testcases) != 1)
        return 1;

    if (testcases < 63 && (1ULL << testcases) < numbers) {
        for (j = 0; j < testcases; j++) {
            if (scanf("%lld", &check) != 1)
                return 1;
            counter = 0;
            
            for (z = 0; z < numbers; z++) {
                counter += (check < data[z]);
            }
            printf("%d\n", counter);
        }
    } else {
        qsort(data, numbers, sizeof(*data), cmpfunc);
        for (j = 0; j < testcases; j++) {
            if (scanf("%lld", &check) != 1)
                return 1;

            size_t a = 0, b = numbers;
            while (a < b) {
                size_t m = a + (b - a) / 2;
                if (data[m] < check)
                    a = m + 1;
                else
                    b = m;
            }
            counter = b;
            printf("%d\n", counter);
        }
    }
    free(data);
    return 0;
}

【讨论】:

  • "只有查找​​次数大于log(N)才有用" ==?有趣的门槛 - 听起来不错。
  • 为什么testcases &lt; 31 而不是,比如说。 testcases &lt; 63?
  • 顺便说一句,很像昨天的comment,而不是qsort(data, numbers, sizeof(long long), cmpfunc);,可以使用qsort(data, numbers, sizeof data[0], cmpfunc);等来形成元素大小。真正的 OP 确实使用了sizeof(long long),这是次要问题。
【解决方案2】:

二进制与线性

而不是线性搜索

    for (z = 0; z < numbers; z++) {
        if (check >= data[z])
            break;
        counter--;
    }

使用二进制数

    found = false;
    int lo = 0;
    int hi = numbers - 1;
    while (lo <= hi) {
      int mid = (hi-lo)/2 + lo;
      if (data[mid] < check) lo = mid + 1;
      else if (data[mid] > check) hi = mid - 1;
      else {
        found = true;
        // found it!
        // Now look for first index less than check with TBD code.
      }
    }  
         
    // Value of lo, hi  can be use to determine the count. 

避免溢出

*(long long*)b - *(long long*)a 可能会溢出。

int cmpfunc(const void *a, const void *b) {
  // return (*(long long*)b - *(long long*)a);
  return (*(long long*)b > *(long long*)a) - (*(long long*)b < *(long long*)a);
}

【讨论】:

  • 恐怕你的二进制查找函数在多次出现的情况下找不到最低索引,因此需要做更多的工作来确定计数。
  • @chqrlie “多次出现”在Now look for first index less than check with TBD code. 部分中介绍。我不想给 OP all 代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-06
  • 2019-07-29
相关资源
最近更新 更多