从未排序的数组中删除重复项

时间:2018-06-19 19:30:32

标签: c++

我正在尝试创建一个函数,以从未排序的int数组中删除重复项。我有一个适用于更多示例的解决方案,但是由于以下输入而失败:

#include<iostream>
using namespace std;

int removeDuplicates(int arr[], int n)
{
    int j = 0;

    for (int i=0; i < n; i++){
        for(int j=0;j<=i;j++){

            if(arr[i]==arr[j]){
                 n--;
                for (int k=i; k<n; k++){
                    arr[k]=arr[k+1];
                }
            }
        }
    }

    return n;
}

// Driver code
int main()
{
    int arr[] = {0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1};
    int n = sizeof(arr) / sizeof(arr[0]);

    n = removeDuplicates(arr, n);

    for (int i=0; i<n; i++)
        cout << arr[i] << " ";

    return 0;
}

此arr示例的输出为0 0 1 0 0,应为0 1。

您看到问题出在哪里吗?谢谢

7 个答案:

答案 0 :(得分:7)

考虑使用std::set<int>记录您已经看到的数字,并使用STL算法执行删除:

#include<iostream>
#include<algorithm>
#include<functional>
#include<set>

// Driver code
int main()
{
    int arr[] = {0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1};
    std::set<int> duplicates;

    auto it = std::remove_if(std::begin(arr), std::end(arr), [&duplicates](int i) {
        return !duplicates.insert(i).second;
    });
    size_t n = std::distance(std::begin(arr), it);

    for (size_t i = 0; i < n; i++)
        std::cout << arr[i] << " ";

    return 0;
}

此代码的作用是将所有重复项都移到数组的末尾,并且std::remove_if返回的迭代器指示新列表的末尾。因此,在开始迭代器和迭代器之间进行迭代可以为您提供没有重复项的数组。

答案 1 :(得分:4)

查看您忘了减少i的内循环

#include<iostream>
using namespace std;

int removeDuplicates(int arr[], int n)
{
    int j = 0;

    for (int i=0; i < n; i++){
        for(int j=0;j<i;j++){

            if(arr[i]==arr[j]){
                n--;
                for (int k=i; k<n; k++){
                    arr[k]=arr[k+1];
                }
                i--;     // you forgot to decrement i
            }
        }
    }

    return n;
}

// Driver code
int main()
{
    int arr[] = {0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1};
    int n = sizeof(arr) / sizeof(arr[0]);

    n = removeDuplicates(arr, n);

    for (int i=0; i<n; i++)
        cout << arr[i] << " ";

    return 0;
}

答案 2 :(得分:1)

在您的职能中

int removeDuplicates(int arr[], int n)
{
    int j = 0;

for (int i=0; i < n; i++){
    for(j=i+1;j<n;)
    {
        if(a[i]==a[j])
        {
            for(int k=j;k<n-1;++k)
                arr[k]=arr[k+1];

            --n;
        }
        else
            ++j;
    }
}

return n;
}

仅当两个值不匹配时才递增j。否则它将跳过一些值

答案 3 :(得分:1)

更新

可能的解决方案是时间为 O(n log n),并且需要 O(m)额外的空间,其中<​​em> m 是输入数组中唯一元素的数量:

template <typename RAIter>
size_t remove_duplicates(RAIter first, RAIter last) {
   using value_type = typename std::iterator_traits<RAIter>::value_type;
   std::map<value_type, size_t> map;
   size_t n = 0;
   for (auto it = first; it != last; ++it) {
      auto & temp = map[*it];
      if (temp == 0) temp = ++n;
   }
   for (auto & e : map)
      *(first + e.second - 1) = e.first;
   return n;
}

还请注意,原始数组的内容在此处已被破坏,但这也是您的尝试。

可能的用法:

int main() {
   static constexpr size_t n = 26;
   std::array<int, n> a = { 0, 0, 1, 0, 3, 2, 1, 1, 0, 1, 0, 0, 2, 2, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1 };

   size_t m = remove_duplicates(std::begin(a), std::end(a));
   for (size_t i = 0; i < m; i++)
       std::cout << a[i] << " ";
   std::cout << std::endl;
}

将打印出0 1 3 2


我将我的解决方案与您的解决方案进行了比较(已通过@Onk_r进行了更正)。对于500,000个元素的输入数组,其随机值从[0,100]开始。我的 O(n log n)解决方案花费了 19毫秒,而您的 O(n 3 解决方案花费了<强> 54秒!很好地演示了复杂性有多重要:)。

答案 4 :(得分:0)

可以,但是您必须以j=1开头,而不是0

错误:

for (int i=0; i < n; i++){
    for(int j=0;j<=i;j++)

解决方案:

for (int i=0; i < n; i++){
    for(int j=1;j<=i;j++){

答案 5 :(得分:0)

int arr1[] = {3, 1, 5, 4, 5, 1, 9, 3, 9, 7};
int size = sizeof(arr1) / sizeof(arr1[0]);

int i, j, k = 0;
int arr2[size];

for(i = 0; i < size; i++)
{
    for(j = 0; j < k; j++)
    {
        if(arr1[i] == arr2[j])
        {
            break;
        }
    }
    if(j == k)
    {
        arr2[k++] = arr1[i];
    }
}

答案 6 :(得分:-3)

请改用集合,因为集合中的所有元素都必须是唯一的。 http://www.cplusplus.com/reference/set/set/