【问题标题】:Sorting array algorithm - duplicate values排序数组算法 - 重复值
【发布时间】:2024-06-26 04:25:02
【问题描述】:

我有一个大小为 N 的整数数组,其中包含重复值,但我不知道值的范围。 我在这个数组中有 n/logn 不同的值,其余的都是重复的。

有没有办法以 O(n) 的时间复杂度和 O(n/logn) 的内存复杂度对其进行排序?

【问题讨论】:

  • 是的,我认为您可以在这些条件下以 O(n) 对该数组进行排序。这是作业吗?
  • @Andras 是的。这对我来说是新的,我有点困惑。
  • 我们一步一步来看看。排序是一个 O(m log m) 操作。你有 m = n/logn 个项目,并且 O(m * log m) = O(n/logn * log(n/logn))
  • 安德拉斯,这不太对。使用 bbst,重复检查会消耗 O(n*log(n/log(n))) 时间。在我的回答中,我使用哈希表来实现重复检查的预期 O(n) 时间。

标签: sorting array-algorithms


【解决方案1】:

也许你可以用这个:

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
int main()
{
    int n=7;

    int v[]={4,1,2,3,2,4,1}; // initial array

    map<int,int>mp;
    vector<int>uni;

    for(int i=0;i<n;i++)
      if(++mp[v[i]]==1) // counting instance of unique values
        uni.push_back(v[i]); // unique value

    sort(uni.begin(),uni.end()); // sorting : O ((n / logn) * logn) = O(n)

    int cur=0;
    for(int i=0;i<uni.size();i++)
    {
        int cnt=mp[uni[i]];
        while(cnt)  // Adding duplicate values
        {
            v[cur++]=uni[i];
            cnt--;
        }
    }

    for(int i=0;i<n;i++) // Printing final sorted array
      cout<<v[i]<<" ";
    cout<<"\n";
return 0;
}

这里uni数组保留唯一值,即最大n / logn值。
然后我们使用具有时间复杂度的 stl sort() 函数 O (n * logn)
如这里总元素n = n / logn。复杂度为O ((n / logn) * logn) = O(n)

所以我们看到,上述方法适用于 O(n) 复杂度和 O(n * logn) 内存。

这里map&lt;&gt;用于统计每个不同值出现的次数。

【讨论】:

  • 更新 mp[v[i]] 可能有 O(n^2) 最坏情况成本(如果所有哈希键发生冲突)。还必须指定散列算法和数据结构以保证 O(logn) 查找和更新
  • 在最坏的情况下你怎么说 O(n^2) ?查找 map(已排序)的复杂度为 O(log N)。所以在最坏的情况下,复杂度将是 O(n * logn) 最大值。
  • 这不太对。使用 bbst,重复检查会消耗 O(n*log(n/log(n))) 时间。在我的回答中,我使用哈希表来实现重复检查的预期 O(n) 时间。正如 Andras 上面提到的,哈希表的最坏情况查找/插入是 O(n);然而,它们通常被使用,就好像它们被摊销了 O(1) 时间(即,它们通常被当作散列函数是完美的一样使用)。
  • @KevinL.Stern 对地图的最坏情况查找是 O(logn)。它使用二进制搜索来搜索一个值
  • 是的,但是您正在执行 n 次查找(对于原始数组的每个元素)。由于 mp 只会增长到 n/log(n) 的大小(因为它只包含非重复项),因此为重复检查提供了 O(n*log(n/log(n)))。
【解决方案2】:

只保留键值对

 for(i=0;i<n;i++)
    {
int key = a[i];
//       if value is in map increase vale of this key
// else add key with value 1 
    } 

现在使用合并排序将此地图数据写入输出数组 希望这能解决你的问题..

【讨论】:

  • 问题是 O(n) 时间复杂度。使用您的流程,它将转到 O(n logn)
【解决方案3】:

冒泡排序需要 O(n^2) 时间并且几乎不需要内存来执行(除了存储原始数组) - 请参阅 http://rosettacode.org/wiki/Sorting_algorithms/Bubble_sort 。不过,快速排序要快得多 - 请参阅 http://rosettacode.org/wiki/Quick_Sort

重复不会影响这些算法中的任何一个

【讨论】:

  • @robin 但是冒泡排序在好的情况下是 O(n)。我需要平均情况下为 O(n) 的算法。
【解决方案4】:

例如,Mergesort 是一个 O(n*lg(n)) 时间算法,空间复杂度为 O(n)。

您可以使用哈希映射将 n/lg(n) 个唯一项提取到它们自己的数组中,并记下每个项出现的次数;这是(预期的)O(n) 时间和 O(n/lg(n)) 空间。现在,您可以在新数组上运行 Mergesort,即:

O(x*lg(x)) 时间 x=n/lg(n) ==
O(n/lg(n) * lg(n/lg(n))) ==
O(n/lg(n) * [lg(n) - lg(lg(n))]) ==
O(n - n*lg(lg(n))/lg(n))

O(x) 空间,x=n/lg(n) ==
O(n/lg(n)) 空间

最后,通过根据哈希图中记录的重复数复制元素,将有序数组扩展为最终结果。

【讨论】: