按升序打印矢量的所有元素直到它为空而没有重复项的最有效方法是什么?
What's the most efficient way to print all elements of vector in ascending order till it's empty without duplicates?
我应该:
- 打印矢量元素排序,不重复。
- 删除从矢量打印的元素。
- 重复前面的步骤,直到矢量为空。
但是似乎我的代码需要更多时间,因此,我寻求优化。我试图用std::vector
和std::set
来完成这项任务。
这是我的方法:
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
int main () {
int n;
cin >> n;
vector<int> v(n);
set<int> st;
for (int i = 0; i < n; i++) {
cin >> v[i];
}
while (!v.empty()) {
for (int i = 0; i < v.size(); i++)
st.insert(v[i]);
for (auto x : st) {
cout << x << ' ';
auto it = find(v.begin(), v.end(), x);
if (it != v.end())
v.erase(it);
}
st.clear();
cout << "n";
}
return 0;
}
例如,输入如下:
7
1 2 3 3 2 4 3
输出将如下所示:
1 2 3 4
2 3
3
您可以使用std::map
而不是std::vector
/std::set
来跟踪数字:
#include <iostream>
#include <map>
int main () {
map<int, int> m;
int size;
std::cin >> size;
for (int i = 0; i != size; i++) {
int number;
std::cin >> number;
++m[number];
}
while (!m.empty()) {
for (auto it = m.begin(); it != m.end(); /*Empty*/) {
const auto number = it->first;
auto& count = it->second;
std::cout << number << ' ';
if (--count == 0) {
it = m.erase(it);
} else {
++it;
}
}
std::cout << "n";
}
}
复杂性现在O(n log(n))
而不是O(n²)
(有大量内部分配(。
由于它覆盖了预期删除的元素,因此std::unique
对此问题没有多大用处。我的解决方案:
std::sort(v.begin(), v.end());
while (!v.empty())
{
int last = v.front();
std::cout << last << " ";
v.erase(v.begin());
for (auto it = v.begin(); it != v.end(); /* no-op */)
{
if (*it == last)
{
++it;
}
else
{
last = *it;
std::cout << last << " ";
it = v.erase(it);
}
}
std::cout << std::endl;
}
您可以通过反转向量的排序,然后向后迭代(因为从靠近向量的背面删除更便宜(来进一步提高性能,但这会使代码进一步复杂化,所以我会说"留给读者练习"。
您可以使用std::map
auto n = 0;
std::cin >> n;
std::map<int, int> mp;
while (--n >= 0) {
auto i = 0;
std::cin >> i;
mp[i] += 1;
}
while (!mp.empty()) {
for (auto& it: mp) {
std::cout << it.first << " ";
it.second--;
}
for (auto it = mp.begin(); it != mp.end(); ++it) {
if (it->second == 0) mp.erase(it);
}
std::cout << "n";
}
没有任何擦除
auto n = 0;
std::cin >> n;
std::map<int, int> mp;
while (--n >= 0) {
auto i = 0;
std::cin >> i;
mp[i] += 1;
}
auto isDone = false;
while (!isDone) {
isDone = true;
for (auto& it: mp) {
if (it.second > 0) std::cout << it.first << " ";
if (--it.second > 0) isDone = false;
}
std::cout << "n";
}
这是使用sort
和vector
的解决方案。 它使用第二个矢量来保存唯一项目并打印它们。
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> v{1,2,3,3,2,4,3};
std::sort(v.begin(), v.end());
std::vector<int>::iterator vit;
while(!v.empty()){
std::vector<int> printer;
std::vector<int>::iterator pit;
vit = v.begin();
while (vit != v.end()){
pit = find(printer.begin(), printer.end(), *vit);
if (pit == printer.end()){
printer.push_back(*vit);
vit = v.erase(vit);
} else {
++vit;
}
}
std::copy(printer.begin(), printer.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << 'n';
}
}
输出:
1 2 3 4
2 3
3
当你提到"效率"时,不清楚(至少对我来说(你在说什么。有些人用它来指代计算复杂性。其他人主要考虑程序员的时间,而另一些人则考虑整体执行速度,无论这是通过计算复杂性的变化获得的,还是(例如(改进的引用位置导致更好的缓存利用率。
所以,有了这个警告,我不确定这是否真的改善了你关心的东西,但无论如何,这就是我认为我会做这项工作的方式:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
// preconditions: input range is sorted
template <class BidiIt>
BidiIt partition_unique(BidiIt begin, BidiIt end) {
auto pivot = end;
for (auto pos = begin; pos != pivot; ++pos) {
auto mid = std::next(pos);
for ( ; mid < pivot && *mid == *pos; ++mid, --pivot)
;
std::rotate(std::next(pos), mid, end);
}
return pivot;
}
template <class It>
void show(It b, It e, std::ostream &os) {
while (b != e) {
os << *b << ' ';
++b;
}
os << 'n';
}
int main() {
std::vector<int> input{ 1, 2, 3, 3, 2, 4, 3 };
std::sort(input.begin(), input.end());
auto begin = input.begin();
auto pos = begin;
while ((pos = partition_unique(begin, input.end())) != input.end()) {
show(begin, pos, std::cout);
begin = pos;
}
show(begin, input.end(), std::cout);
}
我真的不确定是否有可能提高计算复杂性(但它可能是 - 我还没有考虑足够确定一种或另一种方式(。与我已经看到的一些版本相比,这很有可能提高整体速度(例如,由于它只是在同一向量内移动东西,因此它可能比将数据从一个向量复制到另一个向量。
代码是用java编写的,但想法保持不变。
- 首先,我对数组进行排序。现在,我们的想法是创建存储桶。
-
这意味着每行排序的元素就像一个桶。因此,找到每个元素的计数。现在,把这个
element
放进each bucket
,count
次数。如果碰巧存储桶大小较小,请创建一个新存储桶并向其中添加当前元素。 -
最后,打印所有存储桶。
- 时间复杂度对于存储桶的排序和
O(n)
O(nlog(n))
,因为您必须访问每个元素才能打印它。所以,它是渐近O(nlog(n)) + O(n) = O(nlog(n))
的。
法典:
import java.util.*;
public class GFG {
public static void main(String[] args){
int[] arr1 = {1,2,3,3,2,4,3};
int[] arr2 = {45,98,65,32,65,74865};
int[] arr3 = {100,100,100,100,100};
int[] arr4 = {100,200,300,400,500};
printSeries(compute(arr1,arr1.length));
printSeries(compute(arr2,arr2.length));
printSeries(compute(arr3,arr3.length));
printSeries(compute(arr4,arr4.length));
}
private static void printSeries(List<List<Integer>> res){
int size = res.size();
for(int i=0;i<size;++i){
System.out.println(res.get(i).toString());
}
}
private static List<List<Integer>> compute(int[] arr,int N){
List<List<Integer>> buckets = new ArrayList<List<Integer>>();
Arrays.sort(arr);
int bucket_size = 0;
for(int i=0;i<N;++i){
int last_index = i;
if(bucket_size > 0){
buckets.get(0).add(arr[i]);
}else{
buckets.add(newBucket(arr[i]));
bucket_size++;
}
for(int j=i+1;j<N;++j){
if(arr[i] != arr[j]) break;
if(j-i < bucket_size){
buckets.get(j-i).add(arr[i]);
}else{
buckets.add(newBucket(arr[i]));
bucket_size++;
}
last_index = j;
}
i = last_index;
}
return buckets;
}
private static List<Integer> newBucket(int value){
List<Integer> new_bucket = new ArrayList<>();
new_bucket.add(value);
return new_bucket;
}
}
输出
[1, 2, 3, 4]
[2, 3]
[3]
[32, 45, 65, 98, 74865]
[65]
[100]
[100]
[100]
[100]
[100]
[100, 200, 300, 400, 500]
这就是我想出的: http://coliru.stacked-crooked.com/a/b3f06693a74193e5
关键思想:
- 排序向量
- 通过迭代打印。如果值与上次打印的值不同,只需打印该值
- 删除唯一元素。 我已经用我称之为inverse_unique做到了这一点。 STD 库带有一种称为 Unique 的算法,它将删除所有重复项。 我颠倒了这个,以便它只保留所有都柏林人。
所以我们根本没有内存分配。 我看不出如何使算法更有效率。 我们只是在做最低限度的事情,它完全按照人类的思维方式完成。
我用几种组合测试了它。 希望它没有错误;-P
法典:
#include <iostream>
#include <algorithm>
#include <vector>
template<class ForwardIt>
ForwardIt inverse_unique(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
auto one_ahead = first+1;
auto dst = first;
while(one_ahead != last)
{
if(*first == *one_ahead)
{
*dst = std::move(*first);
++dst;
}
++first;
++one_ahead;
}
return dst;
}
void print_unique(std::vector<int> const& v)
{
if(v.empty()) return;
// print first
std::cout << v[0] << ' ';
auto last_printed = v.cbegin();
// print others
for(auto it = std::next(std::cbegin(v)); it != std::cend(v); ++it)
{
if(*it != *last_printed)
{
std::cout << *it << ' ';
last_printed = it;
}
}
std::cout << "n";
}
void remove_uniques(std::vector<int> & v)
{
auto new_end = inverse_unique(std::begin(v), std::end(v));
v.erase(new_end, v.end());
}
int main ()
{
std::vector<int> v = {1, 2, 3, 3, 2, 4, 3};
std::sort(std::begin(v), std::end(v));
while (!v.empty())
{
print_unique(v);
remove_uniques(v);
}
return 0;
}
编辑:更新inverse_unique功能。 现在应该很容易理解。
半生不熟 http://coliru.stacked-crooked.com/a/c45df1591d967075
略微修改了计数排序。
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <map>
int main() {
std::vector<int> v{1,2,3,3,2,4,3};
std::map<int, int> map;
for (auto x : v)
++map[x];
while(map.size()) {
for(auto pair = map.begin(); pair != map.end(); ) {
std::cout << pair->first << ' ';
if (!--pair->second)
pair = map.erase(pair);
else
++pair;
}
std::cout << "n";
}
return 0;
}
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 通过JNI传递数据数组的最快方法是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 在另一个类视图中添加最多2个图表的正确方法是什么
- 在C++中样板"冷/never_inline"错误处理技术的最佳方法是什么?
- 在 c++ 中对类中的 c 字符串动态数组进行排序的最佳方法是什么?
- 在C++中包含原型文件的正确方法是什么?
- 在 OpenCV C++ 中估计基本矩阵之前对相应点进行归一化的正确方法是什么?
- 在PostgreSQL中根据它们的ID选择大量行的最快方法是什么?
- 在OSX上使用CMake将Adobe的XMP工具包构建为共享库的最简单方法是什么?
- 将一系列整数放入类的最佳方法是什么?
- 从长整整转换为uint64_t的推荐方法是什么?
- C++:使用方法调用析构函数的顺序是什么?
- 将此布尔值传递给此函数的最有效方法是什么?