目录
那么就可以利用二路归并实现K路归并了(O(N * K * logK))
算法题案例,最经典的莫过于这一题(Kth smallest sum)
先来看看二路合并(O(max{N, M}))
#include <algorithm>
#include <vector>
#include <utility>
#include <ranges>
std::vector<int> merge(std::vector<std::pair<int, int>>& pairs){
//两路向量,用vector<pair>表示
auto length { pairs.size() };
std::vector<int> result {};
result.reserve(length << 1 | 1);
std::ranges::sort(pairs);
auto i {0U};
auto j {0U};
//这里压行了,就是普通的有序数组合并
while(i < length || j < length){
if(j >= length || (i < length
&& pairs[i].first < pairs[j].second))
result.emplace_back(pairs[i].first);
else
result.emplace_back(pairs[j].second);
}
return result;
}
那么就可以利用二路归并实现K路归并了(O(N * K * logK))
#include <algorithm>
#include <vector>
#include <utility>
#include <ranges>
//一样的二路归并
std::vector<int> merge(std::vector<int>& one, std::vector<int>& two){
auto N { one.size() };
auto M { two.size() };
std::ranges::sort(one);
std::ranges::sort(two);
std::vector<int> result;
result.reserve((N + M) << 1 | 1);
auto i {0U};
auto j {0U};
while(i < N || j < M){
if(j >= M || (i < N
&& one[i] < two[j]))
result.emplace_back(one[i]);
else
result.emplace_back(one[j]);
}
return result;
}
//利用二路归并实现K路归并
std::vector<int> KMerge(std::vector<std::vector<int>>& matrix){
auto K { matrix.size() };
auto i {0U};
auto j {K - 1};
//DC
while(!(K == 1)){
while(i < j)
matrix[i] = merge(matrix[i++], matrix[j--]);
//特判,K为奇数
if(i == j)
matrix[i-1] = matrix[i];
K = (K + 1) >> 1U;
}
return matrix[0];
}
优先队列优化
#include <array>
#include <queue>
#include <algorithm>
#include <functional>
#include <cstdint>
#include <ranges>
constexpr std::size_t N { 64U };
constexpr std::size_t K { 32U };
auto merge(std::array<std::array<int32_t, N>, K>& matrix,
std::array<int32_t, K> counter) {
for (auto & row : matrix) std::ranges::sort(row, std::ranges::greater());
std::priority_queue<std::pair<std::size_t, int32_t>> Q;
for (auto i {0U}; i < K; ++i) Q.emplace(i, matrix[i][--counter[i]]);
std::size_t cnt {};
std::array<int32_t, N * K> result;
while (!Q.empty()) {
auto [row, val] = Q.top();
Q.pop();
result[cnt++] = val;
if (counter[row]) Q.emplace(row, matrix[row][--counter[row]]);
}
return result;
}
特殊地,我们有多路链表的归并
#include <vector>
#include <limits>
#include <initializer_list>
#include <ranges>
#include <queue>
class integer_list{
struct Node{
struct Node *__next__ {nullptr};
int __value__ {0};
} *dummy {new Node {__next__ : nullptr,
__value__ : std::numeric_limits<int>::min()} };
public:
void insert(int value){
Node *U { new Node{ __next__ : dummy->__next__,
__value__ : value} };
dummy->__next__ = U;
}
constexpr integer_list(void) noexcept = default;
integer_list(std::initializer_list<int> li){
for(auto integer : li | std::views::reverse) insert(integer);
}
static integer_list
merge(std::vector<integer_list>& lists){
std::priority_queue<std::pair<int, Node *>> Q;
for(auto head : lists | std::views::transform([](auto list){ return list.dummy->__next__; } ) )
if(head) Q.emplace(head->__value__, head);
integer_list result;
while(!Q.empty()){
auto [value, pointer] = Q.top();
Q.pop();
result.insert(value);
if(pointer->__next__)
Q.emplace(pointer->__next__->__value__,
pointer->__next__);
}
return result;
}
};
算法题案例,最经典的莫过于这一题(Kth smallest sum)
给你一个 m * n 的矩阵 ,以及一个整数 k
你可以从每一行中选出 1 个元素形成一个数组。
返回所有可能数组中的第 k 个 最小 数组和。
#include <array>
#include <queue>
#include <algorithm>
#include <functional>
#include <cstdint>
#include <ranges>
#include <cstdio>
constexpr int32_t N { 64U };
constexpr int32_t K { 32U };
std::array<std::array<int32_t, N>, K> matrix {};
std::array<int32_t, K> counter {};
void merge(int32_t source, int32_t mediate, int32_t destine){
std::priority_queue<std::pair<int32_t, int32_t>> Q;
for(int i {}; i < counter[mediate]; ++i)
Q.emplace(i, matrix[source][0] + matrix[mediate][i]);
for(int i {}; i < counter[destine]; ++i){
auto [column, value] = Q.top();
Q.pop();
matrix[destine][i] = value;
if(column)
Q.emplace(--column, value - matrix[source][column] + matrix[mediate][column + 1]);
}
}
int main(void){
int32_t kk {};
while(~std::scanf("%d", &kk) && kk){
for(int i {}; i < kk; ++i){
std::scanf("%d", &counter[i]);
for(auto j {0}; j < counter[i]; ++j)
std::scanf("%d", &matrix[i][j]);
std::ranges::sort(matrix[i], std::ranges::greater());
}
for(int i {}; i < kk; ++i) merge(0, i, 0);
for(int i {}; i < counter[0]; ++i)
std::printf("%d%c", matrix[0][i], " \n"[i == counter[0] - 1]);
}
return 0;
}