我们有一组S {1,10,100,1000,10000}
。现在我们输入一个整数x
(例如x
= 4
)。
现在,我们必须将集合x
的集合产品的每个元素添加到集合本身。所以最后
S={1,10,100,1000,10000,4,40,400,4000,40000}
[{S
最初不仅限于5个条目]
我们只需要访问集合中的初始元素。 我尝试了类似的方法:
for(auto i=s.begin();i!=s.end();i++)
{
s.insert((*i)*x);
}
由于集合的大小不断增加,因此无法获得理想的结果。
我尝试的另一种方法是将所有倍数(*i)*x
存储在另一个临时集合/向量中,并在以后与s合并。
但是由于原始数据集很大,因此会增加时间复杂度。
有优化吗?
答案 0 :(得分:3)
由于std::set
是有序的,并且迭代器不会因插入而无效,因此只要不插入到仍要迭代的范围,就可以在迭代时简单地插入。
如果我们可以假设所有数字都是正数,那么我们可以反向进行迭代,因为相乘的结果总是大于输入:
for (auto it = S.rbegin(); it != S.rend(); ++it)
S.insert(*it*x);
如果x
为负,且集合仅包含正,则迭代顺序无关紧要。如果集合中可能包含负数,这将变得更具挑战性。
但是,由于原始数据集非常庞大,因此会增加时间复杂度。
将N个元素插入std::set
中是O(N log N)。合并std::set
为O(N log N)。合并方法不会增加渐近时间的复杂性。
但是,如果您要使用std::unordered_set
,则合并方法通常为O(N)。但是在最坏的情况下,它仍然是O(N log N)。我建议对无序集合使用合并方法。
答案 1 :(得分:1)
如注释中所述,使用临时集最简单。在C ++ 17中,您可以将std::set::merge
与转换为右值的临时集一起使用:
#include <algorithm>
std::set<int> s2;
std::transform(s1.cbegin(), s1.cend(), std::inserter(s2, s2.end()),
[](int orig){ return 4*orig; });
s1.merge(std::move(s2));
否则,请注意,插入时不会使集合中的迭代器无效。将其与集合是有序的事实结合在一起的,并且在您描述的情况下(缩放现有值大于原始值,但小于或等于下一个现有值),可以像这样循环执行这个:
for (auto it = s1.begin(); it != s1.end(); ++it)
it = s.insert(*it*4).first;
为了减少限制,您可以使用以下更详细的循环:
for (std::set<int>::iterator it1 = s.begin(), it2; it1 != s.end();
it1 = std::next(it1) == it2 ? std::next(it1, 2) : it2)
it2 = s.insert(*it1*4).first;
答案 2 :(得分:1)
您在这里。
#include <iostream>
#include <set>
#include <iterator>
std::set<int> & update( std::set<int> &s, int value )
{
for ( auto it = rbegin( s ); it != rend( s ); ++it )
{
s.insert( *it * value );
}
return s;
}
int main()
{
std::set<int> s = { 1, 10, 100, 1000, 10000 };
for ( const auto &value : s )
{
std::cout << value << ' ';
}
std::cout << '\n';
for ( const auto &value : update( s, 4 ) )
{
std::cout << value << ' ';
}
std::cout << '\n';
return 0;
}
程序输出为
1 10 100 1000 10000
1 4 10 40 100 400 1000 4000 10000 40000
根据C ++ 20标准(22.2.6关联容器)
9 insert和emplace成员不应影响以下内容的有效性: 容器的迭代器和引用,以及擦除成员 仅使迭代器和对已删除元素的引用无效。
或更通用的方法
#include <iostream>
#include <set>
#include <iterator>
std::set<int> & update( std::set<int> &s, int value )
{
auto partition = s.lower_bound( 0 );
for ( auto it = rbegin( s ); it != std::set<int>::reverse_iterator( partition ); ++it )
{
s.insert( *it * value );
}
for ( auto it = begin( s ); it != partition; ++it )
{
s.insert( *it * value );
}
return s;
}
int main()
{
std::set<int> s = { -10000, -1000, -100, -10, -1, 1, 10, 100, 1000, 10000 };
for ( const auto &value : s )
{
std::cout << value << ' ';
}
std::cout << '\n';
for ( const auto &value : update( s, 4 ) )
{
std::cout << value << ' ';
}
std::cout << '\n';
return 0;
}
程序输出为
-10000 -1000 -100 -10 -1 1 10 100 1000 10000
-40000 -10000 -4000 -1000 -400 -100 -40 -10 -4 -1 1 4 10 40 100 400 1000 4000 10000 40000