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

Posted

技术标签:

【中文标题】从 C++ 中的排序数组中删除重复项【英文标题】:Removing duplicates from a sorted array in c++ 【发布时间】:2021-12-12 01:54:47 【问题描述】:

我正在尝试从已排序的数组中删除重复项。代码为一个测试用例提供了正确的输出,但未能为多个测试用例提供正确的输出。我用其他方法得到了正确的输出,但这种方法有什么问题?我该如何解决这个问题?

#include <iostream>
#include<bits/stdc++.h>
using namespace std;

int main() 
    // your code goes here
    int t;
    cin>>t;
    
    while(t--)
    
    int n;
    cin>>n;
    int a[n],i,k,temp,count;
    
    for(i=0;i<n;i++)
        cin>>a[i];
    
    
    sort(a,a+n);
   
    count=0;
    for(i=0;i<n;i++)
        
        if(a[i-1]-a[i]==0)
            
            temp = a[i];
            count++;
            for(k=i;k<n;k++)
                a[k] = a[k+1];  
            
            
           
    
    
    for(i=0;i<n-count;i++)
        cout<<a[i]<<" ";
    
    cout<<endl;
    
        
    
    

【问题讨论】:

我在 3 次罢工后停止阅读:#include&lt;bits/stdc++.h&gt; 然后using namespace std; 最后是int a[n]。请考虑从介绍性 C++ 书籍开始,而不是使用hackerrank 或 leetcode 学习编码 Why should I not #include <bits/stdc++.h>? 和 Why is “using namespace std;” considered bad practice? 我认为新的打击应该是那些发布代码的人,其输出依赖于 std::cin 的输入。基本上,如果您想从 SO 那里得到答案,则永远没有充分的理由发布使用 std::cin 的代码,除非您的问题与 std::cin 有关。 en.cppreference.com/w/cpp/algorithm/unique Why aren't variable-length arrays part of the C++ standard? 【参考方案1】:

这样的变长数组

int a[n],i,k,temp,count;

不是标准的 C++ 功能。相反,您应该使用标准容器std::vector&lt;int&gt;

这个 if 语句

if(a[i-1]-a[i]==0)

由于表达式 a[i-1] 而在 i 等于 0 时调用未定义的行为。

这个for循环也存在同样的问题

        for(k=i;k<n;k++)
            a[k] = a[k+1];  
        

k 等于n - 1 由于表达式a[k+1]

此外,每次找到重复元素后复制所有元素的效率也很低。

请注意,可以使用标准算法std::unique 代替您的循环。

如果要使用 for 循环,那么您可以实现类似以下的内容

#include <iostream>

int main() 

    int a[] =  1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5 ;
    const size_t N = sizeof( a ) / sizeof( *a );
    
    size_t n = 0;
    
    for ( size_t i = 0; i < N; i++ )
    
        if ( i == 0 || a[i] != a[n-1] )
        
            if ( i != n  ) a[n] = a[i];
            ++n;
        
    
    
    for ( size_t i = 0; i < n; i++ )
    
        std::cout << a[i] << ' ';
    
    std::cout << '\n';
    
    return 0;

程序输出是

1 2 3 4 5 

如果使用标准算法std::unique,那么解决方案会更简单,因为不需要自己编写for循环。

#include <iostream>
#include <iterator>
#include <algorithm>

int main() 

    int a[] =  1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5 ;

    auto last = std::unique( std::begin( a ), std::end( a ) );
    
    for ( auto first = std::begin( a ); first != last; ++first )
    
        std::cout << *first << ' ';
    
    std::cout << '\n';
    
    return 0;

程序输出和上图一样就是

1 2 3 4 5 

【讨论】:

【参考方案2】:

我发现您的代码有两个主要问题,都是从数组中越界读取:

if(a[i-1]-a[i]==0) 将在某一时刻被i==0 调用,访问元素a[-1]

这里:

for(k=i;k<n;k++)
   a[k] = a[k+1];  

在最后一次循环迭代中,当k == n-1数组元素a[n]被访问时,也是越界访问。

【讨论】:

以上是关于从 C++ 中的排序数组中删除重复项的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 中的数组中删除重复项 [关闭]

从排序数组中删除重复项(不同的最终结果)

力扣算法笔记—1_删除排序数组中的重复项(数组)

前端与算法 leetcode 26. 删除排序数组中的重复项

26.删除排序数组中的重复项

删除排序数组中的重复项