Skip to content

Commit dd77dcd

Browse files
committed
Add C++ solutions for Chapter 11 (Trees)
1 parent 502f5bd commit dd77dcd

14 files changed

+558
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "ds/TreeNode.h"
2+
using ds::TreeNode;
3+
4+
/**
5+
* Definition of TreeNode:
6+
* struct TreeNode {
7+
* int val;
8+
* TreeNode *left;
9+
* TreeNode *right;
10+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
11+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
12+
* };
13+
*/
14+
15+
bool balancedBinaryTreeValidation(TreeNode* root) {
16+
return getHeightImbalance(root) != -1;
17+
}
18+
19+
int getHeightImbalance(TreeNode* node) {
20+
// Base case: if the node is null, its height is 0.
21+
if (!node)
22+
return 0;
23+
// Recursively get the height of the left and right subtrees. If
24+
// either subtree is imbalanced, propagate -1 up the tree.
25+
int leftHeight = getHeightImbalance(node->left);
26+
int rightHeight = getHeightImbalance(node->right);
27+
if (leftHeight == -1 || rightHeight == -1)
28+
return -1;
29+
// If the current node's subtree is imbalanced
30+
// (height difference > 1), return -1.
31+
if (abs(leftHeight - rightHeight) > 1)
32+
return -1;
33+
// Return the height of the current subtree.
34+
return 1 + std::max(leftHeight, rightHeight);
35+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include <limits>
2+
#include "ds/TreeNode.h"
3+
using ds::TreeNode;
4+
5+
/**
6+
* Definition of TreeNode:
7+
* struct TreeNode {
8+
* int val;
9+
* TreeNode *left;
10+
* TreeNode *right;
11+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
12+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
13+
* };
14+
*/
15+
16+
bool binarySearchTreeValidation(TreeNode* root) {
17+
// Start validation at the root node. The root node can contain any
18+
// value, so set the initial lower and upper bounds to -infinity and
19+
// +infinity, respectively.
20+
return isWithinBounds(root, std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
21+
}
22+
23+
bool isWithinBounds(TreeNode* node, int lowerBound, int upperBound) {
24+
// Base case: if the node is null, it satisfies the BST condition.
25+
if (!node)
26+
return true;
27+
// If the current node's value is not within the valid bounds, this
28+
// tree is not a valid BST.
29+
if (!(lowerBound < node->val && node->val < upperBound))
30+
return false;
31+
// If the left subtree isn't a BST, this tree isn't a BST.
32+
if (!isWithinBounds(node->left, lowerBound, node->val))
33+
return false;
34+
// Otherwise, return true if the right subtree is also a BST.
35+
return isWithinBounds(node->right, node->val, upperBound);
36+
}

cpp/Trees/binary_tree_columns.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#include <vector>
2+
#include <unordered_map>
3+
#include <queue>
4+
#include <utility>
5+
#include <algorithm>
6+
#include "ds/TreeNode.h"
7+
using ds::TreeNode;
8+
9+
/**
10+
* Definition of TreeNode:
11+
* struct TreeNode {
12+
* int val;
13+
* TreeNode *left;
14+
* TreeNode *right;
15+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
16+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
17+
* };
18+
*/
19+
20+
std::vector<std::vector<int>> binaryTreeColumns(TreeNode* root) {
21+
if (!root)
22+
return {};
23+
std::unordered_map<int, std::vector<int>> columnMap;
24+
int leftmostColumn = 0, rightmostColumn = 0;
25+
std::queue<std::pair<TreeNode*, int>> queue;
26+
queue.push({root, 0});
27+
while (!queue.empty()) {
28+
TreeNode* node = queue.front().first;
29+
int column = queue.front().second;
30+
queue.pop();
31+
if (node) {
32+
// Add the current node's value to its corresponding list in the hash
33+
// map.
34+
columnMap[column].push_back(node->val);
35+
leftmostColumn = std::min(leftmostColumn, column);
36+
rightmostColumn = std::max(rightmostColumn, column);
37+
// Add the current node's children to the queue with their respective
38+
// column ids.
39+
queue.push({node->left, column - 1});
40+
queue.push({node->right, column + 1});
41+
}
42+
}
43+
// Construct the output list by collecting values from each column in the hash
44+
// map in the correct order.
45+
std::vector<std::vector<int>> res;
46+
for (int i = leftmostColumn; i <= rightmostColumn; i++) {
47+
if (columnMap.count(i)) {
48+
res.push_back(columnMap[i]);
49+
}
50+
}
51+
return res;
52+
}

cpp/Trees/binary_tree_symmetry.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "ds/TreeNode.h"
2+
using ds::TreeNode;
3+
4+
/**
5+
* Definition of TreeNode:
6+
* struct TreeNode {
7+
* int val;
8+
* TreeNode *left;
9+
* TreeNode *right;
10+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
11+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
12+
* };
13+
*/
14+
15+
bool binaryTreeSymmetry(TreeNode* root) {
16+
if (!root)
17+
return true;
18+
return compareTrees(root->left, root->right);
19+
}
20+
21+
bool compareTrees(TreeNode* node1, TreeNode* node2) {
22+
// Base case: if both nodes are null, they're symmetric.
23+
if (!node1 && !node2)
24+
return true;
25+
// If one node is null and the other isn't, they aren't symmetric.
26+
if (!node1 || !node2)
27+
return false;
28+
// If the values of the current nodes don't match, trees aren't symmetric.
29+
if (node1->val != node2->val)
30+
return false;
31+
// Compare the 'node1's left subtree with 'node2's right subtree. If these
32+
// aren't symmetric, the whole tree is not symmetric.
33+
if (!compareTrees(node1->left, node2->right))
34+
return false;
35+
// Compare the 'node1's right subtree with 'node2's left subtree.
36+
return compareTrees(node1->right, node2->left);
37+
}

cpp/Trees/build_binary_tree.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <vector>
2+
#include <unordered_map>
3+
#include "ds/TreeNode.h"
4+
using ds::TreeNode;
5+
6+
/**
7+
* Definition of TreeNode:
8+
* struct TreeNode {
9+
* int val;
10+
* TreeNode* left;
11+
* TreeNode* right;
12+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
13+
* TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
14+
* };
15+
*/
16+
17+
TreeNode* buildBinaryTree(std::vector<int>& preorder, std::vector<int>& inorder) {
18+
// Populate the hash map with the inorder values and their indexes.
19+
std::unordered_map<int, int> inorderIndexesMap;
20+
for (int i = 0; i < inorder.size(); i++) {
21+
inorderIndexesMap[inorder[i]] = i;
22+
}
23+
// Build the tree and return its root node.
24+
int preorderIndex = 0;
25+
return buildSubtree(0, inorder.size() - 1, preorder, inorder, preorderIndex, inorderIndexesMap);
26+
}
27+
28+
TreeNode* buildSubtree(int left, int right, std::vector<int>& preorder, std::vector<int>& inorder,
29+
int& preorderIndex, std::unordered_map<int, int>& inorderIndexesMap) {
30+
// Base case: if no elements are in this range, return nullptr.
31+
if (left > right) {
32+
return nullptr;
33+
}
34+
int val = preorder[preorderIndex];
35+
// Set 'inorder_index' to the index of the same value pointed at by
36+
// 'preorder_index'.
37+
int inorderIndex = inorderIndexesMap[val];
38+
TreeNode* node = new TreeNode(val);
39+
// Advance 'preorder_index' so it points to the value of the next
40+
// node to be created.
41+
preorderIndex++;
42+
// Build the left and right subtrees and connect them to the current
43+
// node.
44+
node->left = buildSubtree(left, inorderIndex - 1, preorder, inorder, preorderIndex, inorderIndexesMap);
45+
node->right = buildSubtree(inorderIndex + 1, right, preorder, inorder, preorderIndex, inorderIndexesMap);
46+
return node;
47+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <stack>
2+
#include <algorithm>
3+
#include "ds/TreeNode.h"
4+
using ds::TreeNode;
5+
6+
/**
7+
* Definition of TreeNode:
8+
* struct TreeNode {
9+
* int val;
10+
* TreeNode *left;
11+
* TreeNode *right;
12+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
13+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
14+
* };
15+
*/
16+
17+
TreeNode* invertBinaryTreeIterative(TreeNode* root) {
18+
if (!root)
19+
return nullptr;
20+
std::stack<TreeNode*> stack;
21+
stack.push(root);
22+
while (!stack.empty()) {
23+
TreeNode* node = stack.top();
24+
stack.pop();
25+
// Swap the left and right subtrees of the current node.
26+
std::swap(node->left, node->right);
27+
// Push the left and right subtrees onto the stack.
28+
if (node->left)
29+
stack.push(node->left);
30+
if (node->right)
31+
stack.push(node->right);
32+
}
33+
return root;
34+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <algorithm>
2+
#include "ds/TreeNode.h"
3+
using ds::TreeNode;
4+
5+
/**
6+
* Definition of TreeNode:
7+
* struct TreeNode {
8+
* int val;
9+
* TreeNode *left;
10+
* TreeNode *right;
11+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
12+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
13+
* };
14+
*/
15+
16+
TreeNode* invertBinaryTreeRecursive(TreeNode* root) {
17+
// Base case: If the node is null, there's nothing to invert.
18+
if (!root)
19+
return nullptr;
20+
// Swap the left and right subtrees of the current node.
21+
std::swap(root->left, root->right);
22+
// Recursively invert the left and right subtrees.
23+
invertBinaryTreeRecursive(root->left);
24+
invertBinaryTreeRecursive(root->right);
25+
return root;
26+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <stack>
2+
#include "ds/TreeNode.h"
3+
using ds::TreeNode;
4+
5+
/**
6+
* Definition of TreeNode:
7+
* struct TreeNode {
8+
* int val;
9+
* TreeNode *left;
10+
* TreeNode *right;
11+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
12+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
13+
* };
14+
*/
15+
16+
int kthSmallestNumberInBSTIterative(TreeNode* root, int k) {
17+
std::stack<TreeNode*> stack;
18+
TreeNode* node = root;
19+
while (!stack.empty() || node) {
20+
// Move to the leftmost node and add nodes to the stack as we go so they
21+
// can be processed in future iterations.
22+
while (node) {
23+
stack.push(node);
24+
node = node->left;
25+
}
26+
// Pop the top node from the stack to process it, and decrement 'k'.
27+
node = stack.top();
28+
stack.pop();
29+
k--;
30+
// If we have processed 'k' nodes, return the value of the 'k'th smallest
31+
// node.
32+
if (k == 0) {
33+
return node->val;
34+
}
35+
// Move to the right subtree.
36+
node = node->right;
37+
}
38+
// If 'k' is larger than the number of nodes in the tree,
39+
// return -1 or handle as needed.
40+
return -1;
41+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <vector>
2+
#include "ds/TreeNode.h"
3+
using ds::TreeNode;
4+
5+
/**
6+
* Definition of TreeNode:
7+
* struct TreeNode {
8+
* int val;
9+
* TreeNode *left;
10+
* TreeNode *right;
11+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
12+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
13+
* };
14+
*/
15+
16+
int kthSmallestNumberInBSTRecursive(TreeNode* root, int k) {
17+
std::vector<int> sortedList = inorder(root);
18+
return sortedList[k - 1];
19+
}
20+
21+
// Inorder traversal function to attain a sorted list of nodes from the BST.
22+
std::vector<int> inorder(TreeNode* node) {
23+
if (!node)
24+
return {};
25+
std::vector<int> left = inorder(node->left);
26+
left.push_back(node->val);
27+
std::vector<int> right = inorder(node->right);
28+
left.insert(left.end(), right.begin(), right.end());
29+
return left;
30+
}

cpp/Trees/lowest_common_ancestor.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include "ds/TreeNode.h"
2+
using ds::TreeNode;
3+
4+
/**
5+
* Definition of TreeNode:
6+
* struct TreeNode {
7+
* int val;
8+
* TreeNode *left;
9+
* TreeNode *right;
10+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
11+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
12+
* };
13+
*/
14+
15+
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
16+
TreeNode* lca = nullptr;
17+
dfs(root, p, q, lca);
18+
return lca;
19+
}
20+
21+
bool dfs(TreeNode* node, TreeNode* p, TreeNode* q, TreeNode*& lca) {
22+
// Base case: a null node is neither 'p' nor 'q'.
23+
if (!node)
24+
return false;
25+
bool nodeIsPOrQ = (node == p || node == q);
26+
// Recursively determine if the left and right subtrees contain 'p'
27+
// or 'q'.
28+
bool leftContainsPOrQ = dfs(node->left, p, q, lca);
29+
bool rightContainsPOrQ = dfs(node->right, p, q, lca);
30+
// If two of the above three variables are true, the current node is
31+
// the LCA.
32+
if (nodeIsPOrQ + leftContainsPOrQ + rightContainsPOrQ == 2)
33+
lca = node;
34+
// Return true if the current subtree contains 'p' or 'q'.
35+
return nodeIsPOrQ || leftContainsPOrQ || rightContainsPOrQ;
36+
}

0 commit comments

Comments
 (0)