mirror of
https://gitlab.com/mfocko/LeetCode.git
synced 2024-11-14 18:07:32 +01:00
244 lines
5.1 KiB
C++
244 lines
5.1 KiB
C++
|
#include <deque>
|
||
|
#include <map>
|
||
|
#include <vector>
|
||
|
|
||
|
// Definition for a binary tree node.
|
||
|
struct TreeNode {
|
||
|
int val;
|
||
|
TreeNode* left;
|
||
|
TreeNode* right;
|
||
|
TreeNode()
|
||
|
: val(0)
|
||
|
, left(nullptr)
|
||
|
, right(nullptr)
|
||
|
{
|
||
|
}
|
||
|
TreeNode(int x)
|
||
|
: val(x)
|
||
|
, left(nullptr)
|
||
|
, right(nullptr)
|
||
|
{
|
||
|
}
|
||
|
TreeNode(int x, TreeNode* left, TreeNode* right)
|
||
|
: val(x)
|
||
|
, left(left)
|
||
|
, right(right)
|
||
|
{
|
||
|
}
|
||
|
};
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
struct TreeNodeHandle {
|
||
|
TreeNode* node;
|
||
|
int x;
|
||
|
int y;
|
||
|
|
||
|
TreeNodeHandle(TreeNode* node, int x, int y)
|
||
|
: node(node)
|
||
|
, x(x)
|
||
|
, y(y)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
bool operator==(const TreeNodeHandle& rhs) const
|
||
|
{
|
||
|
return node == rhs.node && x == rhs.x && y == rhs.y;
|
||
|
}
|
||
|
|
||
|
int value() const
|
||
|
{
|
||
|
return node->val;
|
||
|
}
|
||
|
|
||
|
bool operator<(const TreeNodeHandle& rhs) const
|
||
|
{
|
||
|
if (y != rhs.y) {
|
||
|
return y < rhs.y;
|
||
|
}
|
||
|
|
||
|
if (x != rhs.x) {
|
||
|
return x < rhs.x;
|
||
|
}
|
||
|
|
||
|
return value() < rhs.value();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class verticals {
|
||
|
TreeNode* root;
|
||
|
|
||
|
class verticals_iter {
|
||
|
std::deque<TreeNodeHandle> queue;
|
||
|
|
||
|
void advance()
|
||
|
{
|
||
|
auto& n = queue.front();
|
||
|
|
||
|
if (n.node->left != nullptr) {
|
||
|
queue.push_back(TreeNodeHandle(n.node->left, n.x - 1, n.y + 1));
|
||
|
}
|
||
|
|
||
|
if (n.node->right != nullptr) {
|
||
|
queue.push_back(TreeNodeHandle(n.node->right, n.x + 1, n.y + 1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
verticals_iter(std::deque<TreeNodeHandle> queue)
|
||
|
: queue(queue)
|
||
|
{
|
||
|
if (queue.front().node == nullptr) {
|
||
|
queue.pop_front();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool operator!=(const verticals_iter& other) const
|
||
|
{
|
||
|
return queue != other.queue;
|
||
|
}
|
||
|
|
||
|
verticals_iter operator++()
|
||
|
{
|
||
|
advance();
|
||
|
queue.pop_front();
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
TreeNodeHandle& operator*()
|
||
|
{
|
||
|
return queue.front();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
public:
|
||
|
verticals(TreeNode* root)
|
||
|
: root(root)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
verticals_iter begin() const
|
||
|
{
|
||
|
return verticals_iter(std::deque { TreeNodeHandle(root, 0, 0) });
|
||
|
}
|
||
|
|
||
|
verticals_iter end() const
|
||
|
{
|
||
|
std::deque<TreeNodeHandle> q;
|
||
|
return verticals_iter(q);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
class Solution {
|
||
|
public:
|
||
|
std::vector<std::vector<int>> verticalTraversal(TreeNode* root)
|
||
|
{
|
||
|
std::map<int, std::vector<TreeNodeHandle>> traversals;
|
||
|
|
||
|
int min_x = 0;
|
||
|
int max_x = 0;
|
||
|
|
||
|
for (auto node : verticals(root)) {
|
||
|
traversals[node.x].push_back(node);
|
||
|
|
||
|
min_x = std::min(min_x, node.x);
|
||
|
max_x = std::max(max_x, node.x);
|
||
|
}
|
||
|
|
||
|
std::vector<std::vector<int>> result;
|
||
|
|
||
|
for (int x = min_x; x <= max_x; x++) {
|
||
|
auto& v = traversals[x];
|
||
|
|
||
|
if (v.size()) {
|
||
|
std::sort(v.begin(), v.end());
|
||
|
result.push_back(std::vector<int> {});
|
||
|
|
||
|
for (auto& n : v) {
|
||
|
result.back().push_back(n.value());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#pragma region tests
|
||
|
|
||
|
#include <gtest/gtest.h>
|
||
|
|
||
|
namespace _tests {
|
||
|
|
||
|
TreeNode* construct_tree(const std::vector<int>& values, std::size_t i = 0)
|
||
|
{
|
||
|
if (i >= values.size() || values[i] == -1) {
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
auto tree = new TreeNode(values[i]);
|
||
|
tree->left = construct_tree(values, 2 * i + 1);
|
||
|
tree->right = construct_tree(values, 2 * i + 2);
|
||
|
|
||
|
return tree;
|
||
|
}
|
||
|
|
||
|
void destruct_tree(TreeNode* ptr)
|
||
|
{
|
||
|
if (ptr == nullptr) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
destruct_tree(ptr->left);
|
||
|
destruct_tree(ptr->right);
|
||
|
delete ptr;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
TEST(examples, first)
|
||
|
{
|
||
|
Solution s;
|
||
|
|
||
|
auto t = _tests::construct_tree(std::vector { 3, 9, 20, -1, -1, 15, 7 });
|
||
|
EXPECT_EQ(s.verticalTraversal(t), (std::vector { std::vector { 9 }, std::vector { 3, 15 }, std::vector { 20 }, std::vector { 7 } }));
|
||
|
_tests::destruct_tree(t);
|
||
|
}
|
||
|
|
||
|
TEST(examples, second)
|
||
|
{
|
||
|
Solution s;
|
||
|
|
||
|
auto t = _tests::construct_tree(std::vector { 1, 2, 3, 4, 5, 6, 7 });
|
||
|
EXPECT_EQ(s.verticalTraversal(t), (std::vector { std::vector { 4 }, std::vector { 2 }, std::vector { 1, 5, 6 }, std::vector { 3 }, std::vector { 7 } }));
|
||
|
_tests::destruct_tree(t);
|
||
|
}
|
||
|
|
||
|
TEST(examples, third)
|
||
|
{
|
||
|
Solution s;
|
||
|
|
||
|
auto t = _tests::construct_tree(std::vector { 1, 2, 3, 4, 6, 5, 7 });
|
||
|
EXPECT_EQ(s.verticalTraversal(t), (std::vector { std::vector { 4 }, std::vector { 2 }, std::vector { 1, 5, 6 }, std::vector { 3 }, std::vector { 7 } }));
|
||
|
_tests::destruct_tree(t);
|
||
|
}
|
||
|
|
||
|
TEST(submission, first)
|
||
|
{
|
||
|
Solution s;
|
||
|
|
||
|
auto t = _tests::construct_tree(std::vector { 3, 1, 4, 0, 2, 2 });
|
||
|
EXPECT_EQ(s.verticalTraversal(t), (std::vector { std::vector { 0 }, std::vector { 1 }, std::vector { 3, 2, 2 }, std::vector { 4 } }));
|
||
|
_tests::destruct_tree(t);
|
||
|
}
|
||
|
|
||
|
int main(int argc, char** argv)
|
||
|
{
|
||
|
::testing::InitGoogleTest(&argc, argv);
|
||
|
return RUN_ALL_TESTS();
|
||
|
}
|
||
|
|
||
|
#pragma endregion /* tests */
|