基于公共元素组合整数对
combine pairs of integers based on common element
假设我有一对整数,例如 (1,3)、(5,6)、(7,8)、(3,9) 那么我想根据它们之间的共同元素将此对组合成唯一的集合,即我可以组合 (1,3) 和 (3,9),因为它们之间是共同的,所以上述输入的最终输出应该是这样的 (1,3,9)、(5,6)、(7,8)一种方法可能是遍历这个数组,并根据公共元素将其组合并从数组中删除第二对,我认为这很耗时。在 C/C++ 中执行此操作的有效方法是什么?
一种有效的方法是将其视为图形连接问题。创建一个图形,其中节点是整数对,如果两个节点对应的对具有公共元素,则在两个节点之间添加无向边。现在,在此图中找到连接的组件,并构造由组件中的节点对应的对的并集形成的集合。
查找连接的组件需要O(E)
时间,如果有n
对,则可能会O(n^2)
时间。合并它们都可以用类似heap
的结构来完成,每次插入需要O(log n)
。因此运行时O(E + n log n)
最多是O(n^2)
。复杂性可能会低得多,具体取决于有多少对具有共同的元素。
我会使用从int
到shared_ptr<list<int>>
的地图,list
超过vector
,因为这是一个很好的splice
用例:
class Combiner {
std::unordered_map<int, std::shared_ptr<std::list<int>>> map;
public:
void addPair(const std::pair<int, int>& p) {
auto a = map.find(p.first);
auto b = map.find(p.second);
// 4 cases: (1) both found the same list, (2) both found different lists,
// (3) one found a list, (4) neither found a list
if (a != map.end()) {
if (b != map.end()) {
if (a->second == b->second) {
// (1) nothing to do, done
}
else {
// (2) have to combine our lists
a->second->splice(a->second.end(), *(b->second));
b->second = a->second;
}
}
else {
// (3), add p.second to a
a->second->push_back(p.second);
map.insert(std::make_pair(p.second, a->second));
}
}
else {
if (b != map.end()) {
// (3), add p.first to b
b->second->push_back(p.first);
map.insert(std::make_pair(p.first, b->second));
}
else {
// (4), make a new list
auto new_list = std::make_shared<std::list<int>>();
new_list->push_back(p.first);
new_list->push_back(p.second);
map.insert(std::make_pair(p.first, new_list));
map.insert(std::make_pair(p.second, new_list));
}
}
}
您希望容器使用哪些类型? 它们是设置的吗?
#include <algorithm>
#include <set>
#include <list>
#include <iostream>
void dump( const std::string & label, const std::list< std::set< int > > & values )
{
std::cout << label << std::endl;
for( auto iter : values )
{
std::cout << "{ ";
for( auto val : iter )
std::cout << val << ", ";
std::cout << "}, ";
}
std::cout << std::endl;
}
void combine( std::list< std::set< int > > & values )
{
for( std::list< std::set< int > >::iterator iter = values.begin(); iter != values.end(); ++iter )
for( std::list< std::set< int > >::iterator niter( iter ); ++niter != values.end(); )
if( std::find_first_of( iter->begin(), iter->end(), niter->begin(), niter->end() ) != iter->end() )
{
iter->insert( niter->begin(), niter->end() );
values.erase( niter );
niter = iter;
}
}
int main( int argc, char ** argv )
{
std::list< std::set< int > > to_process = { { 1, 3 }, { 5, 6 }, { 7, 8 }, { 3, 9 } };
dump( "Before", to_process );
combine( to_process );
dump( "After", to_process );
to_process = { { 1, 3 }, { 5, 6 }, { 7, 8 }, { 3, 9 }, { 9, 13 }, { 8, 11 } };
dump( "Before", to_process );
combine( to_process );
dump( "After", to_process );
to_process = { { 1, 2 }, { 5, 6 }, { 7, 8 }, { 3, 9 }, { 9, 13 }, { 8, 13 } };
dump( "Before", to_process );
combine( to_process );
dump( "After", to_process );
return 0;
}
输出:
Before
{ 1, 3, }, { 5, 6, }, { 7, 8, }, { 3, 9, },
After
{ 1, 3, 9, }, { 5, 6, }, { 7, 8, },
Before
{ 1, 3, }, { 5, 6, }, { 7, 8, }, { 3, 9, }, { 9, 13, }, { 8, 11, },
After
{ 1, 3, 9, 13, }, { 5, 6, }, { 7, 8, 11, },
Before
{ 1, 2, }, { 5, 6, }, { 7, 8, }, { 3, 9, }, { 9, 13, }, { 8, 13, },
After
{ 1, 2, }, { 5, 6, }, { 3, 7, 8, 9, 13, },
相关文章:
- 如何反转整数参数包
- 如何组合两个整数向量
- 如何计算数组整数的总可能组合
- 三重限制的正整数组合的非递归枚举
- 在编译时将整数和分数部分宏组合成一个新的宏或双精度
- 数据的所有组合都是产品的两个整数
- 在数组C++中创建所有可能的非唯一整数组合
- 如何将字符串和整数组合成单个字符串 (C++)
- 整数/浮点数/字符串值之间的操作,组合太多
- 组合位 - 将字符组合为整数C++
- 正整数 uniq 的组合(顺序不重要)
- 将 n 个整数组合成一个唯一的表示形式
- 实现欧几里得除法,根据两个正整数的线性组合编写这两个正整数的最大公约数
- 运行整数数组所有组合的算法
- 基于公共元素组合整数对
- 使用removeDifferent()和removeSame()组合两组整数
- 计算N个整数组合的绝对值
- 使用逻辑OR ||组合两个整数
- 如何将三个整数组合成一个唯一的标记,使标记在c++中保持整数
- 如何在vc++中将4个整数组合成一个整数