Problem
The goal is to perform the following transformation:
Additionally, if two rows can be merged, they are combined into one:
Code
I wrote the following algorithm to solve this problem:
#include <vector>
#include <iostream>
#include <algorithm>
using Matrix = std::vector<std::vector<int>>;
using Column = std::vector<int>;
Column max_col(const Matrix &v) {
return *std::max_element(v.begin(), v.end(),
[](auto& lhs, auto& rhs)
{
return lhs.size() < rhs.size();
});
}
bool is_element_in_next_rows(const Matrix &v, int element,int row) {
for (auto& col : v) {
if (row >= static_cast<int>(col.size())) continue; // out of range
if (std::lower_bound(col.begin()+row+1,col.end(),element) !=
std::upper_bound(col.begin()+row+1,col.end(),element)) {
return true;
}
}
return false;
}
int min_element_in_row(const Matrix &v, int row) {
int min_element = max_col(v)[row];
for (auto& col : v) {
if (row >= static_cast<int>(col.size())) continue; // out of range
if (col[row] != 0) min_element = std::min(min_element, col[row]);
}
return min_element;
}
void print_elements(const Matrix &v) {
for (auto& i : v) {
for (auto& j : i) {
std::cout << j << " ";
}
std::cout << std::endl;
}
}
void organize_elements(Matrix &v) {
for (auto& col : v) {
std::sort(col.begin(),col.end());
}
auto current_max_col = max_col(v);
for (int row{0}; current_max_col.begin()+row!=current_max_col.end(); ++row) {
int min_element = min_element_in_row(v,row);
for(auto& col : v) {
if (row >= static_cast<int>(col.size())) continue; // out of range
int candidate = col[row];
if (candidate > min_element) {
if (is_element_in_next_rows(v,candidate,row)) {
col.push_back(0);
std::rotate(col.begin()+row,col.end()-1,col.end());
}
}
}
current_max_col = max_col(v);
}
}
int main() {
Column c1 = {5,6,8,11};
Column c2 = {2,5,3,1,4,6};
Column c3 = {8,7,2,4,5,3,1};
Matrix v;
v.push_back(c1);
v.push_back(c2);
v.push_back(c3);
std::cout << "original: \n";
print_elements(v);
organize_elements(v);
std::cout << "organized: \n";
print_elements(v);
return 0;
}
Which produces the following output:
original:
5 6 8 11
2 5 3 1 4 6
8 7 2 4 5 3 1
organized:
0 0 0 0 5 6 8 11
1 2 3 4 5 6
1 2 3 4 5 7 8
Questions
I particularly don't like this part of my code:
auto current_max_col = max_col(v);
for (int row{0}; current_max_col.begin()+row!=current_max_col.end(); ++row) {
// ....
current_max_col = max_col(v);
}
I also don't like that I have to do this cast:
if (row >= static_cast<int>(col.size())) continue; // out of range
Is there a way to do this check better?
The fact that I need to declare current_max_col
out of the for
, and then update it inside the loop. Any idea how to avoid this?
Any other ideas about how to solve this problem? Any other tips? Thank you!
[1..8]
and no other value exceeds8
. Is there some hidden restriction (otherwise,max_col
looks suspicious)? \$\endgroup\$