如何在不使用任何其他类型的数据结构的情况下删除数组中的重复元素?
我只是很难换班。请帮忙!!
例如,如果我有这个数组: string arr [] = {" helo"," helo"," dog"}
如何让它成为{" helo"," dog"}?
答案 0 :(得分:2)
在C ++中,您可以使用命名空间std
中定义的唯一函数模板。这适用于已排序的容器将删除重复项并将迭代器返回到唯一序列的末尾。
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
std::vector<std::string> v{ "helo", "helo", "dog" };
std::sort( v.begin(), v.end() );
std::vector<std::string>::iterator last;
last = std::unique( v.begin(), v.end()); // "dog", "helo", "helo"
// ^
for ( std::vector<std::string>::iterator it = v.begin(); it != last; ++it) {
std::cout << *it << " ";
}
std::cout << "\n"; // output: dog helo
}
这个模板函数也可以使用指向普通数组的指针begin
和end
迭代器(指针是迭代器,迭代器是抽象概念)。但是要小心彻底了解std::unique()详细说明的内容 - 因为您可以看到容器的元素必须首先进行排序以达到您的预期,容器的大小不会被unique
更改。
没有什么能阻止你编写自己独特的东西:
template<class ForwardIt>
ForwardIt unique(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
ForwardIt result = first;
while (++first != last) {
if (!(*result == *first)) {
*(++result) = std::move(*first);
}
}
return ++result;
}
如果要删除其余元素,这些元素遵循唯一元素,您可以删除它们:
std::sort( v.begin(), v.end() );
v.erase( unique( v.begin(), v.end() ), v.end() );
答案 1 :(得分:0)
以下是我将如何处理一个我不想重新排序的未排序数组:
// returns how many elements were *removed*
template <typename T>
int RemoveDups (T a [], int n)
{
int shift = 0;
for (int i = 1; i < n; ++i)
{
int j = i - 1 - shift;
for ( ; j >= 0; --j)
if (a[i] == a[j])
break;
if (j < 0) // not a duplicate
a[i - shift] = std::move(a[i]);
else
shift += 1;
}
return shift;
}
我接受数组作为输入的方式不是最好的方法;使用std::array
或一对类似迭代器的对象。但我想要最简单的答案。
以下是对正在发生的事情的描述:
我们维护一个变量shift
,它总是跟踪每个元素需要移回多少个插槽,或者相当于在当前元素之前已经删除了多少个元素。
从第二个元素开始(因为显然第一个元素不是任何东西的副本),我们将i
元素与它之前的所有元素进行比较。如果这个元素不等于它们中的任何一个,那么这是一个“好”的元素并且需要保留,所以我们将它移回shift
个点。否则,我们将它留在以后要覆盖的位置(或者不是;我们不关心)并且只增加shift
(因为现在还有一个元素已被删除并需要被移除。)
i
元素与之前所有元素的比较从shift
之前的i
位置开始并向后,因为我们知道之前的shift
元素是被删除而不需要(其中所有“好”元素都已被移回。)
就是这样。该算法的时间复杂度为O(n^2)
且稳定。
如果您知道元素已经排序,则只能将每个元素与之前的shift - 1
个点进行比较,并在O(n)
中完成。
如果您不介意重新排序数据,可以先在O(n*log(n))
中对其进行排序,然后使用O(n)
方法总计O(n*log(n))
。