私は現在_vector<int> c
_を含む_{1,2,2,4,5,5,6}
_を含み、c
が_{1,4,6}
_を持つように重複した数を削除したいです。インターネット上の多くのソリューションが重複の1つを削除するだけでなく、重複した数のすべての出現箇所を削除しようとしています。
c
を常にソートします。
私は現在持っています
_#include <iostream>
#include <vector>
int main() {
vector<int> c{1,2,2,4,5,5,6};
for (int i = 0; i < c.size()-1; i++) {
for (int j=1; j<c.size();j++){
if(c[i] == c[j]){
// delete i and j?
}
}
}
}
_
現在の要素と次の要素を比較できるように、2つのループを使用しようとしました。これが私の疑問が蹴ったところです。私が問題に正しく近づいているかどうかはかなりありません。
私の問題に取り組む方法についての助けを得ることができますか?
std::unique
/std::copy_if
と同様に、次のことができます。
void keep_unique(std::vector<int>& v){
auto it = v.begin();
auto w = v.begin();
while (it != v.end())
{
auto next = std::find_if(it, v.end(), [&](int e){ return e != *it; });
if (std::distance(it, next) == 1) {
if (w != it) {
*w = std::move(*it);
}
++w;
}
it = next;
}
v.erase(w, v.end());
}
逆に繰り返します ベクトル内の最後の要素を消去するだけなので、消去時に。また、他のデータ構造を割り当てる必要はありません。O(N)
の操作を引き起こさずに要素シフトを発生させません。
発生したすべての要素について、隣接する要素が等しいかどうかを確認し、そうであれば、その要素のすべてのインスタンスを削除します。
ベクトルをソートするか、少なくとも重複によってグループ化される必要があります。
#include <iostream>
#include <vector>
int main()
{
std::vector<int> c {1, 2, 2, 4, 5, 5, 6};
for (int i = c.size() - 1; i > 0;)
{
const int n = c[i];
if (c[i - 1] == n)
{
while (c[i] == n)
{
c.erase(c.begin() + i--);
}
}
else
{
i--;
}
}
//output result
for (auto it : c)
{
std::cout<<it;
}
std::cout << std::endl;
}
_
Output: 146
_
実際のO(N) "Sentinel値を使用した実装:
#include <iostream>
#include <vector>
#include <limits>
#include <algorithm>
int main()
{
std::vector<int> c { 1, 2, 2, 4, 5, 5, 6 };
const int sentinel = std::numeric_limits<int>::lowest(); //assumed that no valid member uses this value.
for (int i = 0; i < c.size() - 1;)
{
const int n = c[i];
if (c[i + 1] == n)
{
while (c[i] == n)
{
c[i++] = sentinel;
}
}
else
{
i++;
}
}
c.erase(std::remove(c.begin(),c.end(),sentinel), c.end());
for (auto it : c) std::cout<< it << ' ';
}
_
一般に、それらを繰り返しながらコンテナから削除するときには非常に注意しなければなりません。 C++ STLは、ネストされたループを使用するよりも簡単かつより速く(平均的に)行うことができます。
_#include <vector>
#include <algorithm>
#include <unordered_set>
int main() {
std::vector<int> c{1,2,2,4,5,5,6};
std::unordered_multiset<int> unique( c.begin(), c.end() );
c.erase(std::remove_if(c.begin(),c.end(),[&](const auto& e){return unique.count(e)>1;}),c.end());
for(auto e: c){
std::cout<<e<<' ';
}
}
//Output: 1 4 6
_
あるいは、_std::map<int,std::size_t>
_を使用してこのように発生することをカウントすることもできます。
これは、実行時エラーを回避するためにイテレータを適切に使用することで達成できます。
次のコードを見てください。
#include <iostream>
#include <vector>
int main() {
std::vector<int> c{1,2,2,4,5,5,6};
for (auto it = c.begin(); it != c.end(); ){
auto it2 = it;
advance(it2, 1);
bool isDuplicate = false;
for(; it2 != c.end(); ++it2){
if(*it == *it2){
c.erase(it2);
isDuplicate = true;
}
}
if(isDuplicate){
auto it3 = it;
advance(it3, 1);
c.erase(it);
it = it3;
}else{
it++;
}
}
for (auto it = c.begin(); it != c.end(); it++){
std::cout<<*it<<" ";
}
}
_
出力:
1 4 6
_
使用する std :: remove_if 後部に複数回発生するアイテムを移動してから消去します。
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> V {1,2,2,4,5,5,6};
auto it = std::remove_if(V.begin(), V.end(), [&](const auto& val)
{
return std::count(V.begin(), V.end(), val) > 1;
});
V.erase(it, V.end());
for (const auto& val : V)
std::cout << val << std::endl;
return 0;
}
_
出力:
1
4
6
_