【问题标题】:How to deal with Leetcode Question "Check If Array Pairs Are Divisible by k"?如何处理 Leetcode 问题“检查数组对是否可被 k 整除”?
【发布时间】:2021-01-25 06:55:51
【问题描述】:

这是来自 Leetcode 的一个问题,如下所示。

"给定一个偶数长度为 n 的整数数组 arr 和一个整数 k。 我们希望将数组精确地划分为 n / 2 对,使得每对的总和可以被 k 整除。 如果你能找到方法,则返回 true,否则返回 false。”

下面列出未完成的答案,

#include <stdio.h>
#include <limits.h>
#include <stdbool.h>

bool main() {
    int arr[] = {1, 2, 3, 4, 5, 10, 6, 7, 8, 9};
    int k = 5;
    int arrSize = sizeof(arr)/sizeof(arr[0]);
    int pairs = arrSize / 2;

    for (int i = 0; i < arrSize && arr[i] != INT_MIN; i++) {
        for (int j = i + 1; j < arrSize && arr[j] != INT_MIN; j++) {
            if ((((long)arr[i] + arr[j]) % k) == 0) {
                pairs--;
                if (pairs == 0)
                    return true;
                arr[j] = INT_MIN;
                break;
            }
        }
    }
    return false;
}

除了答案是对还是错之外,我对 for 循环的多个条件的使用感到困惑。 我预计外部 for 循环将运行到 i == arrSize - 1,但出乎我的意料,它会在 i == 1j == 2 处停止。 我将条件从arr[i] != INT_MIN &amp;&amp; i &lt; arrSize 改写为arr[i] != INT_MIN, i &lt; arrSize,然后就可以了。 我更喜欢&amp;&amp;,但就是不知道为什么它不起作用。 我不知道为什么会这样。 请阐明它。 附言只留下负面评价真是太可怕了。

【问题讨论】:

  • 由于读取超出数组末尾,该程序具有未定义的行为。在尝试访问数组之前,您必须先进行数组结束测试。查看 C 中逻辑运算符的短路评估
  • @paddy 怎么会!我将最后一个索引控制为arrSize - 1。不是吗?
  • 当然,i &lt; arrSizei == arrSize 时会评估为假,但发生这种情况之前你已经测试了arr[i] != INT_MIN,这意味着你从arr[arrSize] 和那 是未定义的行为。在您的j-loop 中也是如此。
  • @paddy 你是对的。但现在我只关注 for 循环中的多个条件问题。这就是我的问题。
  • 问题是,如果您的程序中有未定义的行为,而您忽略了它,那么您所追求的问题可能只是一个幽灵。除了看到未定义的行为之外,我不会进一步分析您的程序。这就是我停下来的地方。

标签: arrays c


【解决方案1】:

当前测试arr[i] != INT_MIN &amp;&amp; i &lt; arrSize 不正确,因为arr[i] 在测试i 是否为有效索引之前已被读取。

此外,您将值设置为INT_MIN 以指定它们应该被忽略,但循环应该继续。要实现这一点,您应该编写:

for (int i = 0; i < arrSize; i++) {
    if (arr[i] == INT_MIN)
        continue;
    for (int j = i + 1; j < arrSize; j++) {
        if (arr[j] == INT_MIN)
            continue;
        if ((((long long)arr[i] + arr[j]) % k) == 0) {
            pairs--;
            if (pairs == 0)
                return true;
            arr[j] = INT_MIN;
            break;
        }
    }
}

但请注意,这种方法存在问题:

  • 您修改了数组,这可能会造成问题
  • INT_MIN 是一个合法的 int 值,如果该值在开始时存在于数组中,则算法将失败。建议使用单独的数组来跟踪使用过的条目。
  • arr[i] + arr[j] 可能会溢出:如果数组元素的类型具有相同的大小,则转换为 (long)(long long) 可能不够。你可以避免这个问题,将测试重写为if ((arr[i] % k + arr[j] % k) % k == 0),假设abs(k) &lt;= INT_MAX / 2
  • 如果未使用的条目没有匹配的条目,您可以立即返回 false。

这是修改后的版本:

#include <stdio.h>
#include <stdbool.h>

bool check_array(int *arr, int arrSize, int k) {
    if (arrSize % 2)
        return false;
    bool used[arrSize];
    for (int i = 0; i < arrsize; i++)
         used[i] = false;
    for (int i = 0; i < arrSize; i++) {
        if (used[i])
            continue;
        for (int j = i + 1; j < arrSize; j++) {
            if (used[j])
                continue;
            if ((arr[i] % k + arr[j] % k) % k == 0) {
                used[i] = used[j] = true;
                break;
            }
        }
        if (!used[i])
            return false;
    }
    return true;
}

int main() {
    int arr[] = { 1, 2, 3, 4, 5, 10, 6, 7, 8, 9 };

    if (check_array(arr, sizeof(arr) / sizeof(arr[0]), 5)) {
        printf("array matches criteria\n");
        return 1;
    } else {
        printf("array does not match criteria\n");
        return 1;
    }
    return 0;
}

【讨论】:

    【解决方案2】:

    您应该只忽略您设置为INT_MIN 的值。这可以写成例子

    if (arr[i] == INT_MIN)
        continue;
    

    你写的类似于

    if (arr[i] == INT_MIN)
        break;
    

    不可能continue 写入简单的条件表达式。

    逗号运算符通过实际上删除这个错误的逻辑使其工作 - 通过丢弃值(尽管您仍然在越界访问数组,这会导致到未定义的行为)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-12
      • 1970-01-01
      • 2018-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-26
      • 2012-10-16
      相关资源
      最近更新 更多