#include #include class Solution { struct indices { int x; int y; bool operator==(const indices &other) const = default; indices &operator+=(const indices &other) { x += other.x; y += other.y; return *this; } friend indices operator+(indices left, const indices &right) { return left += right; } int operator[](const std::vector> &mat) const { return mat[y][x]; } }; struct spiral_indices { spiral_indices(const std::vector> &matrix) : x_bounds{-1, static_cast(matrix[0].size())}, y_bounds{-1, static_cast(matrix.size())} {} bool done() const { return !in_bounds(idx); } spiral_indices &operator++() { // update bounds and change the direction if cannot move if (!in_bounds(idx + d)) { // change the direction d = {-d.y, d.x}; // get the magnitude of the vector auto flat_d = d.x + d.y; // decide whether we're moving x or y bounds auto &bounds = d.x ? x_bounds : y_bounds; if (flat_d > 0) { bounds.x++; } else { bounds.y--; } } idx += d; return *this; } int operator[](const std::vector> &mat) const { return idx[mat]; } private: indices idx{0, 0}; indices d{1, 0}; indices x_bounds, y_bounds; bool in_bounds(const indices &idx) const { return (x_bounds.x < idx.x && idx.x < x_bounds.y) && (y_bounds.x < idx.y && idx.y < y_bounds.y); } }; public: std::vector spiralOrder(const std::vector> &matrix) { std::vector spiral; for (spiral_indices idx{matrix}; !idx.done(); ++idx) { spiral.push_back(idx[matrix]); } return spiral; } }; int main() { Solution s; assert((s.spiralOrder({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}) == std::vector{1, 2, 3, 6, 9, 8, 7, 4, 5})); assert((s.spiralOrder({{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}) == std::vector{1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7})); return 0; }