I am working on the LeetCode problem 102. Binary Tree Level Order Traversal:
Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
I want to print all nodes at a given level in one group. I have found a way to do this in this answer on Stack Overflow.
But this answer uses recursion while my code does not. I would like to know where I am going wrong in my approach.
For example given input : [1,2,3,4,null,null,5]
My output : [[1],[4],[5]]
Expected output: [[1],[2,3],[4,5]]
#include <iostream>
#include <vector>
#include <map>
#include <deque>
using namespace std;
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) {}
};
vector<vector<int>> levelOrder(TreeNode *root) {
deque<TreeNode *> queue;
map<int, vector<int>> myMap;
vector<vector<int>> retvector;
vector<int> addvector;
int level = 0;
if (root != nullptr) {
queue.push_back(root);
addvector.push_back(root->val);
//retvector.push_back(addvector);
myMap.insert(pair<int, vector<int>>(level, addvector));
}
while (!queue.empty()) {
TreeNode *ptr = queue.front();
queue.pop_front();
addvector.clear();
if (ptr->left != nullptr) {
addvector.push_back(ptr->left->val);
queue.push_back(ptr->left);
}
if (ptr->right != nullptr) {
addvector.push_back(ptr->right->val);
queue.push_back(ptr->right);
}
if (!addvector.empty()) {
//retvector.push_back(addvector);
myMap.insert(pair<int, vector<int>>(level, addvector));
level++;
addvector.clear();
}
}
for (int i = 0; i < level; i++) {
retvector.push_back(myMap[i]);
}
return retvector;
}
int main() {
TreeNode root, left1, left2, right1, right2;
left2 = TreeNode(4);
left1 = TreeNode(2, &left2, nullptr);
right2 = TreeNode(5);
right1 = TreeNode(3, nullptr, &right2);
root = TreeNode(1, &left1, &right1);
vector<vector<int>> v = levelOrder(&root);
for (auto &i: v) {
for (auto &j: i)
cout << j << " ";
cout << endl;
}
}
You don't need a map, nor a queue, nor a level number.
Instead alternate with 2 vectors that have the nodes of 2 consecutive levels.
Also, in your logic, addvector can at the most have 2 entries, which shows why this approach cannot work.
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<TreeNode *> parentLevel, childLevel;
vector<vector<int>> retvector;
vector<int> addvector;
if (root != nullptr) {
parentLevel.push_back(root);
}
while (!parentLevel.empty()) {
addvector.clear();
childLevel.clear();
for (auto parent : parentLevel) {
addvector.push_back(parent->val);
if (parent->left != nullptr) {
childLevel.push_back(parent->left);
}
if (parent->right != nullptr) {
childLevel.push_back(parent->right);
}
}
retvector.push_back(addvector);
parentLevel = childLevel;
}
return retvector;
}
};
Explanation
Let's take the example tree:
1
/ \
2 3
/ \
4 5
parentLevel starts out with [1] (actually the TreeNode having 1).
Then the outer loop starts, where the inner loop will take every node in that parentLevel vector and put its value in addvector. So in this iteration, addvector will be [1].
In the same process all direct children of these nodes are collected in childLevel, so there we will have the nodes [2, 3].
The inner loop then finishes, and addvector is appended to the result. So retvector will be [[1]].
Now the same should happen with the children, so we promote childLevel to be the parentLevel for the next iteration of the outer loop.
And so we start the next iteration of the outer loop with parentLevel having [2, 3]. Again, the corresponding values get pushed to an empty addvector, which will then have [2, 3]. At the same time childLevel gets populated with the child nodes [4, 5].
The second iteration of the outer loop will end by extending retvector to [[1],[2,3]], and so the process continues level by level...
Related
Question: Implement Inorder Traversal iteratively.
My Attempt: (results in an infinite loop that I haven't been able to debug) any help or suggestions greatly appreciated
/**
* 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) {}
* };
*/
#include <vector>
#include <stack>
#include <unordered_set>
using namespace std;
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
//iterative sol:
vector<int> sol;
stack<TreeNode*> dfs;
dfs.push(root);
unordered_set<TreeNode*> visited;
visited.insert({root});
TreeNode* temp;
while (!dfs.empty()) {
if (dfs.top()->left != nullptr && visited.find(dfs.top()->left) == visited.end()) {
dfs.push(dfs.top()->left);
visited.insert({dfs.top()->left});
}
else {
sol.push_back(dfs.top()->val);
temp = dfs.top();
dfs.pop();
if (temp->right != nullptr && visited.find(temp->right) == visited.end()) {
dfs.push(temp->right);
visited.insert({temp->right});
}
}
}
return sol;
}
};
EDIT: I don't have the specific internal definitions of the TreeNode, but if you want to run the problem, checkout: https://leetcode.com/problems/binary-tree-inorder-traversal/
Here is the problem :
dfs.push(dfs.top()->left);
visited.insert(dfs.top()->left);
You are pushing to stack (then dfs.top() will change) and then accessing dfs.top()->left in the next line.
You are modifying the stack in the first line here
dfs.push(dfs.top()->left);
visited.insert({dfs.top()->left});
what you want to do is to mark the previous dfs.top()->left as visited, but you are adding more element on top of the stack and thus the new dfs.top() is a different one.
To solve this problem you should use store the previous dfs.top()->left in a different variable.
As a best practice, the variable or object you are working on should be immutable, since the stack is not immutable don't use its top while inserting into it or doing some other computations. Instead store your required variable into something immutatble like temp here
temp = dfs.top();
if (temp->left != nullptr && visited.find(temp->left) == visited.end()) {
dfs.push(temp->left);
visited.insert({temp->left});
}
else {
sol.push_back(dfs.top()->val);
dfs.pop();
if (temp->right != nullptr && visited.find(temp->right) == visited.end()) {
dfs.push(temp->right);
visited.insert({temp->right});
}
}
It only takes 2 simple rules to implement an iterative in-order traversal.
If you're at node X, then:
If X has a right child, then move to the right child, and follow as many left links as possible to find the next node.
Otherwise, find the closest ancestor of X on the right, i.e., the closest ancestor whose left subtree contains X. If there is no such ancestor then you're done.
If your tree doesn't have parent links, then you'll need a stack to store the right ancestors, but there's no need for a visited set:
vector<int> inorderTraversal(TreeNode* tree) {
vector<int> ret;
stack<TreeNode *> nextParents;
for(;tree; tree = tree.left) {
nextParents.push(tree);
}
while(!nextParents.empty()) {
tree = nextParents.pop();
ret.push_back(tree->val);
for(tree = tree.right; tree; tree = tree.left) {
nextParents.push(tree);
}
}
return ret;
}
I have already some sort of solution for the problem:
Given an integer N, construct all possible binary search trees with N nodes.
except that I include trees with root the minimum and maximum value but this is not my main concern.
I want to put emphasis into correctly using the move semantics and memory management in C++ (as a learning exercice).
My solution is:
#include <vector>
struct Node{
int value;
Node *left = nullptr;
Node *right = nullptr;
};
std::vector<Node*> createListNodes(int min, int max)
{
// ordered vector with i.e. {0,1,2,3,4}
Node *node = new Node;
if (min == max)
{
node->value = min;
return std::vector<Node*> {node}; // it is a leaf node
}
std::vector<Node*> alterantive{};
for (int i=min; i<=max; i++)
{
auto left = createListNodes(min,i-1); // for the left side
auto right = createListNodes(i+1,max); // for the left side
if (left.size() == 0) // if node i has just one child and it is in the right
{
for (auto elem_right : right)
{
alterantive.emplace_back(new Node{i,nullptr,elem_right});
}
}
else if (right.size() == 0) // if node i has just one child and it is in the left
{
for (auto elem_left : left)
{
alterantive.emplace_back(new Node{i,elem_left,nullptr});
}
}
for (auto elem_left : left)
{
for (auto elem_right : right)
{
alterantive.emplace_back(new Node{i,elem_left,elem_right});
}
}
}
return alterantive;
}
int main()
{
int N = 4;
std::vector<Node*> combinations = createListNodes(0, N);
}
So would like to know:
Improvements I could made to my basic design, I would prefer not to use smart pointers yet but the raw ones, to make it more memory efficient (copying less values from one side to the other ...)
General improvements in the code, even though my main focus is on memory management, memory leaks ...
Similar to this example:
I wanna make a linked list node connections as shown in the picture but I am stuck, how should I proceed?
class Node{
public:
int id;
int count;
int *next;
int *prev;
Node(int a): id(a), count(0), next(NULL), prev(NULL) {};
Node(const int & ss, const int &c): id(ss), count( c), next(NULL), prev(NULL) {};
Right now I have these and some other setter and getter functions.
That picture is a graph adjacency list where:
There is an array of 5 elements, one per graph node.
Each array element is a (singly linked) list of adjacent node numbers.
The value of each list element is the graph node number this graph node is adjacent to.
Node* adjacency_list[5] is enough to represent that.
Working example:
#include <iostream>
class Node {
public:
int id;
Node *next;
Node *prev;
Node(int a): id(a), next(0), prev(0) {}
};
Node* make_list(std::initializer_list<int> ids) {
Node* head = 0;
Node** ptail = &head;
for(int id : ids) {
*ptail = new Node(id - 1);
ptail = &((**ptail).next);
}
return head;
}
void print_list(Node** heads, int count) {
for(int i = 0; i < count; ++i) {
std::cout << (i + 1) << ": ";
for(Node* n = heads[i]; n; n = n->next)
std::cout << (n->id + 1) << ',';
std::cout << '\n';
}
}
int main() {
Node* adjacency_list[5] = {};
adjacency_list[1 - 1] = make_list({2, 3, 4});
adjacency_list[2 - 1] = make_list({4, 5});
adjacency_list[3 - 1] = make_list({1, 2, 5});
adjacency_list[4 - 1] = make_list({5});
adjacency_list[5 - 1] = make_list({4});
print_list(adjacency_list, 5);
}
Output:
1: 2,3,4,
2: 4,5,
3: 1,2,5,
4: 5,
5: 4,
In a real-world application you may like to make sure that the allocated memory doesn't leak (it leaks in this example) or use std::forward_list or some other standard or 3rd-party container.
I am stuck on a Huffman Tree problem. I think my code has a clear logic. I first built a priority queue to compare the weight of Node and place the Node with minimum weight at the top of the priority queue.
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct Node
{
int weight, depth;
Node *left, *right;
Node(int value):weight(value), left(NULL),right(NULL),depth(0){}
Node(int value, Node* left_leaf_ptr, Node* right_leaf_ptr) : weight(value), left(left_leaf_ptr), right(right_leaf_ptr), depth(0) {}
};
//this struct is used for priority queue
struct Greater
{
bool operator () (Node a, Node b){return a.weight > b.weight;}
};
// find whether the node is a leaf
bool isleaf(Node node) { return node.left == NULL && node.right == NULL; }
// update the depth of Huffman Tree
void update_depth(Node& node,int depth)
{
node.depth=depth;
if (! isleaf(node))
{
depth++;
update_depth(*node.left,depth);
update_depth(*node.right, depth);
}
}
Node build_Huffman_tree(priority_queue<Node, vector<Node>, Greater> weights_queue)
{
while (weights_queue.size() > 1)
{
Node l1=weights_queue.top();
weights_queue.pop();
Node l2 = weights_queue.top();
weights_queue.pop();
Node l3(l1.weight + l2.weight, &l1, &l2);
update_depth(l3, 0);
weights_queue.push(l3);
}
return weights_queue.top();
}
int main()
{
priority_queue<Node, vector<Node>, Greater> weights_queue;
weights_queue.push(Node(1));
weights_queue.push(Node(1));
weights_queue.push(Node(3));
weights_queue.push(Node(5));
Node root = build_Huffman_tree(weights_queue);
return 0;
}
When I run this program in C++ 11, in the second while loop inside the function build_Huffman_tree, it creates a Node of weight 2, depth 4700. What's worse is that this Node seems endless. i.e. its left child tree has weight 2, and this child tree has its left child tree of weight 2, and so on...
So please point out the reason of my program's failure and teach me how to fix it.
Unique Binary Search Trees
Given n, generate all structurally unique
BST's (binary search trees) that store values 1...n.
For example, Given n = 3,
your program should return all 5 unique
BST's shown below.
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
Personally I think, time complexity = O(n^n), n is the input.
But what's more tight time complexity?
C++
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
#include <vector>
using namespace std;
class Solution {
public:
vector<TreeNode *> generateTrees(int n) {
vector<TreeNode *> list;
// Input validation.
if (n <= 0) {
list.push_back(NULL);
return list;
}
int left = 1;
int right = n;
generateTrees(left, right, list);
return list;
}
void generateTrees(int left, int right, vector<TreeNode *> &list) {
// Base case.
if (left > right) {
list.push_back(NULL);
return;
}
for (int i = left; i <= right; i ++) {
vector<TreeNode *> left_trees;
generateTrees(left, i - 1, left_trees);
vector<TreeNode *> right_trees;
generateTrees(i + 1, right, right_trees);
for (vector<TreeNode *>::iterator left_it = left_trees.begin();
left_it != left_trees.end(); left_it ++) {
TreeNode *leftTree = *left_it;
for (vector<TreeNode *>::iterator right_it = right_trees.begin();
right_it != right_trees.end(); right_it ++) {
TreeNode *rightTree = *right_it;
TreeNode *root = new TreeNode(i);
root->left = leftTree;
root->right = rightTree;
list.push_back(root);
}
}
}
}
};
Given n nodes, the total number of the binary search trees is the Catalan Number, please refer to this link: http://en.wikipedia.org/wiki/Catalan_number. So, the time complexity is also O(Catalan(n)).