问:给定一个整数数组 nums,如果任何值在数组中出现至少两次,则返回 true,如果每个元素都不同,则返回 false。(完整问题说明: https:

bool containsDuplicate(int* nums, int numsSize) {
    int i, j;
    int k = 0;
    int f = 0;
    for (i = k + 1; i < numsSize; i++)
    {
        if (nums[k] == nums[i])
        {
            f = 1;
            break;
        }

        if (i == numsSize - 1)
        {
            k++;
            i = k;
        }
    }

    if (f == 1)
        return true;
    else 
        return false;
}   

为什么上述代码在 leetcode 上显示超出时间限制?请解决可能与上述代码相关的问题。

我试图仅在一个循环中检查条件而不嵌套它们,但代码失败

3

  • 1
    你测试过你的代码吗(除了在 leetcode 上运行它)?我建议添加一个main函数,提供一个值数组并调试你的函数。


    – 


  • 3
    @bodo 在这种情况下,问题不在于代码本身有误,而在于算法效率问题。


    – 

  • @Chris 也许吧,但一般来说,如果没有main函数和输入,我们就无法验证代码不包含可能导致无限循环的错误。


    – 


最佳答案
2

如果您仍然需要执行大量操作,那么减少循环次数不会改善时间复杂度。即使只有一个循环,您的代码也是如此O(N^2):只是所有这些迭代现在都在一个循环中。

O(N)您可以使用哈希集(预期总体)或平衡二叉搜索树(总体)等数据结构更有效地查找重复项O(N log N)

C 的标准库中没有这些,但您可以使用它们qsort对数组进行排序(标准没有规定时间复杂度保证,但通常O(N log N)至少是平均水平)。排序后,可以通过检查相邻元素对轻松检测重复项。

int comp(const void* a, const void *b) {
    return *(int*) a - *(int*) b;
}
bool containsDuplicate(int* nums, int numsSize) {
    qsort(nums, numsSize, sizeof *nums, comp);
    for (int i = 1; i < numsSize; ++i) if (nums[i] == nums[i - 1]) return true;
    return false;
}

4

  • 该表达式*(int*) a - *(int*) b;可能存在算术溢出,不是吗?


    – 

  • @MikeNakis 不在问题的背景下,其中所有元素的nums绝对值都被限制为最多 10^9。


    – 


  • 呃,我没有在原作者提供的问题描述中看到这样的限制。


    – 

  • @MikeNakis 完整问题陈述在这里:


    – 

您基本上已经使用以下代码将单个循环转换为嵌套循环。如果只编写嵌套循环,则会更清晰。

        if (i == numsSize - 1)
        {
            k++;
            i = k;
        }

显式嵌套循环:

bool containsDuplicate(int* nums, int numsSize) {
    for (int i = 0; i < numsSize - 1) {
        for (int j = i + 1; j < numsSize; j++) {
            if (nums[i] == nums[j])
                return 1;
        }
    }

    return 0;
}

这种嵌套循环方法,无论是按照您已有的方式编写还是明确使用嵌套循环,运行时复杂度都是 O(n^2)。对于非常小的数组来说,这并不重要,但对于较大的数组来说,它太慢了,而且 Leetcode 不仅会使用非常小的数组进行测试,而且还会使用非常大的样本量专门测试此类算法问题。

如果重复项位于样本数组的非常靠前的位置,那么您的代码确实会表现得很好,因为它会短路,但 Leetcode 不太可能对您如此友善。

相反,假设您首先对数组进行排序(具有 O(n * log n)复杂度的良好排序),然后在排序后的数组上运行单个 O(n)循环以检查连续重复项。

通过比较不同的样本大小,我们可以看出你采用的方法的规模有多小。显然,Leetcode 可能不会要求你的代码对包含十亿个整数的数组进行排序,但一百个或一千个整数是完全合理的,而且在这种规模下已经有很大差异了。

n n * log n n^2 比较
10 33 100 ~3倍
100 664 10,000 ~15倍
1,000 9,966 1,000,000 ~100x
10,000 132,880 1亿 ~750x
100,000 1,661,000 10,000,000,000 ~6,000 倍
1,000,000 19,930,000 1,000,000,000,000 ~50,000 倍
10,000,000 235,230,000 100,000,000,000,000 ~425,000 倍
1亿 2,657,500,000 10,000,000,000,000,000 ~3,760,000 倍
1,000,000,000 299亿 1,000,000,000,000,000,000 ~33,445,000 倍