You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻找未排序数组中重复元素的最优时间复杂度算法

寻找数组中重复元素的最优算法

问题描述

给定包含n个元素的未排序数组,元素取值范围为1到n-1,其中恰好存在一个重复值,要求找到该重复元素并追求最优时间复杂度。

你提供的C++算法如下:

int tab[] = { 1,6,7,8,9,4,2,2,3,5 };
int arrSize = sizeof(tab)/sizeof(tab[0]);

for (int i = 0; i < arrSize; i++) {
    tab[tab[i] % arrSize] = tab[tab[i] % arrSize] + arrSize;
}

for (int i = 0; i < arrSize; i++) {
    if (tab[i] >= arrSize * 2) {
        std::cout << i;
        break;
    }
}

关于时间复杂度的上限

首先明确:不可能达到优于O(n)的时间复杂度。因为要确定重复元素,你至少需要遍历数组中的每个元素一次——假设存在算法只遍历少于n个元素,必然遗漏至少一个元素,而这个遗漏元素恰好可能是重复项,无法保证结果正确。所以O(n)是该问题的时间复杂度下限。

更优的算法(空间或操作效率优化)

你的算法是O(n)时间、O(1)空间,但会修改原数组。以下是几种同样O(n)时间的优化方案:

1. 原地交换法(允许修改原数组)

逻辑更直观,无需取模和加法操作,常数时间开销更小:

int findDuplicate(int nums[], int n) {
    while (nums[0] != nums[nums[0]]) {
        std::swap(nums[0], nums[nums[0]]);
    }
    return nums[0];
}

2. 快慢指针法(Floyd判圈算法,不修改原数组)

利用数组元素取值特性,将数组视为带环链表,重复元素即为环的入口点,完全不改动原数组:

int findDuplicate(const int nums[], int n) {
    int slow = nums[0];
    int fast = nums[nums[0]];
    // 找到快慢指针相遇点
    while (slow != fast) {
        slow = nums[slow];
        fast = nums[nums[fast]];
    }
    // 找到环的入口(重复元素)
    slow = 0;
    while (slow != fast) {
        slow = nums[slow];
        fast = nums[fast];
    }
    return slow;
}

3. 数学求和法(代码简洁,需注意溢出)

计算1到n-1的理论和,与数组实际求和的差值即为重复元素,代码最简洁,但n较大时可能出现数值溢出:

int findDuplicate(int nums[], int n) {
    int expectedSum = (n-1)*n / 2;
    int actualSum = 0;
    for (int i = 0; i < n; i++) {
        actualSum += nums[i];
    }
    return actualSum - expectedSum;
}

总结

所有正确算法的时间复杂度都是O(n),这是问题的下限。你可以根据是否允许修改原数组、是否担心数值溢出等场景选择不同方案,它们在常数时间或空间特性上各有优劣,但时间复杂度无法再优化。

内容的提问来源于stack exchange,提问作者hero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 18:48:38