blog/files/blog/leetcode/sort-matrix-diagonally/matrix-sort.cpp
github-actions[bot] 00c23a0553 deploy: e881234412
2024-01-06 16:30:44 +00:00

229 lines
6.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <algorithm>
#include <cassert>
#include <vector>
using matrix = std::vector<std::vector<int>>;
template <typename T>
class diagonal {
using matrix_t = std::vector<std::vector<T>>;
matrix_t& matrix;
std::size_t x;
std::size_t y;
class diagonal_iter {
// we need to keep reference to the matrix itself
std::reference_wrapper<matrix_t> m;
// we need to be able to tell our current position
std::size_t x;
std::size_t y;
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
using iterator_category = std::random_access_iterator_tag;
diagonal_iter(matrix_t& matrix,
std::size_t x,
std::size_t y)
: m(matrix)
, x(x)
, y(y)
{
}
bool operator==(const diagonal_iter& rhs) const
{
return x == rhs.x && y == rhs.y && m.get() == rhs.m.get();
}
diagonal_iter& operator++()
{
// we are moving along the diagonal, so we increment both x and y
// at the same time
x++;
y++;
return *this;
}
reference operator*() const { return m.get()[y][x]; }
// exactly opposite to the incrementation
diagonal_iter operator--()
{
x--;
y--;
return *this;
}
// moving n steps back is same as calling decrementation n-times, so
// we can just return a new iterator and subtract n from both
// coordinates in the matrix
diagonal_iter operator-(difference_type n) const
{
return diagonal_iter { m, x - n, y - n };
}
// here we assume that we are given two iterators on the same diagonal
difference_type operator-(const diagonal_iter& rhs) const
{
assert(m.get() == rhs.m.get());
return x - rhs.x;
}
// counterpart of moving n steps backwards
diagonal_iter operator+(difference_type n) const
{
return diagonal_iter { m, x + n, y + n };
}
// we compare the coordinates, and also assume that those 2 iterators are
// lying on the same diagonal
bool operator<(const diagonal_iter& rhs) const
{
assert(m.get() == rhs.m.get());
return x < rhs.x && y < rhs.y;
}
};
public:
diagonal(matrix_t& matrix, std::size_t x, std::size_t y)
: matrix(matrix)
, x(x)
, y(y)
{
}
diagonal_iter begin() const { return diagonal_iter { matrix, x, y }; }
diagonal_iter end() const
{
auto max_x = matrix[y].size();
auto max_y = matrix.size();
// we need to find the distance in which we get out of bounds (either in
// column or row)
auto steps = std::min(max_x - x, max_y - y);
return diagonal_iter { matrix, x + steps, y + steps };
}
};
template <typename T>
class diagonals {
using matrix_t = std::vector<std::vector<T>>;
class diagonals_iter {
matrix_t& m;
std::size_t x;
std::size_t y;
public:
diagonals_iter(matrix_t& matrix, std::size_t x, std::size_t y)
: m(matrix)
, x(x)
, y(y)
{
}
bool operator!=(const diagonals_iter& rhs) const
{
// iterators are not equal if they reference different matrices, or
// their positions differ
return x != rhs.x || y != rhs.y || m != rhs.m;
}
diagonals_iter& operator++()
{
if (y != 0) {
// iterating through diagonals down the first column
y++;
return *this;
}
// iterating the diagonals along the first row
x++;
if (x == m.front().size()) {
// switching to diagonals in the first column
x = 0;
y++;
}
return *this;
}
diagonal<T> operator*() const { return diagonal { m, x, y }; }
};
matrix_t& _matrix;
public:
diagonals(matrix_t& m)
: _matrix(m)
{
}
diagonals_iter begin() { return diagonals_iter { _matrix, 0, 0 }; }
diagonals_iter end() { return diagonals_iter { _matrix, 0, _matrix.size() }; }
};
class Solution {
public:
matrix diagonalSort(matrix mat)
{
// we iterate over the diagonals
for (auto d : diagonals(mat)) {
// and we sort each diagonal
std::sort(d.begin(), d.end());
}
// we take the matrix by copy, so we can sort in-situ and return the copy
// that we sorted
return mat;
}
};
static void test_case_1()
{
// Input: mat = [[3,3,1,1],[2,2,1,2],[1,1,1,2]]
// Output: [[1,1,1,1],[1,2,2,2],[1,2,3,3]]
Solution s;
assert((s.diagonalSort(std::vector { std::vector { 3, 3, 1, 1 },
std::vector { 2, 2, 1, 2 },
std::vector { 1, 1, 1, 2 } })
== std::vector { std::vector { 1, 1, 1, 1 },
std::vector { 1, 2, 2, 2 },
std::vector { 1, 2, 3, 3 } }));
}
static void test_case_2()
{
// Input: mat =
// [[11,25,66,1,69,7],[23,55,17,45,15,52],[75,31,36,44,58,8],[22,27,33,25,68,4],[84,28,14,11,5,50]]
// Output:
// [[5,17,4,1,52,7],[11,11,25,45,8,69],[14,23,25,44,58,15],[22,27,31,36,50,66],[84,28,75,33,55,68]]
Solution s;
assert((s.diagonalSort(std::vector { std::vector { 11, 25, 66, 1, 69, 7 },
std::vector { 23, 55, 17, 45, 15, 52 },
std::vector { 75, 31, 36, 44, 58, 8 },
std::vector { 22, 27, 33, 25, 68, 4 },
std::vector { 84, 28, 14, 11, 5, 50 } })
== std::vector { std::vector { 5, 17, 4, 1, 52, 7 },
std::vector { 11, 11, 25, 45, 8, 69 },
std::vector { 14, 23, 25, 44, 58, 15 },
std::vector { 22, 27, 31, 36, 50, 66 },
std::vector { 84, 28, 75, 33, 55, 68 } }));
}
int main()
{
test_case_1();
test_case_2();
return 0;
}