For example:
Given the following binary tree,
1 <--- / \ 2 3 <--- \ \ 5 4 <---You should return
[1, 3, 4].BFS 遍历tree的变形。!!!
这个题目是求从右边往左边看的树上的值,其实如果知道这一题其实是BFSlevel order traverse tree,每次取每一层的最后那个node的话就是从右往左看树的结果, 所以这一题我是用bfs 取每层的最后那个值。
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> rst;
//sanity check
if (root == NULL) return rst;
queue<TreeNode*> explore;
explore.push(root);
while (!explore.empty()) {
int size = explore.size();
for (int i = 0; i < size; i++) {
TreeNode* tmp = explore.front();
if ( i == size-1) rst.push_back(tmp->val);
explore.pop();
if (tmp->left) explore.push(tmp->left);
if (tmp->right) explore.push(tmp->right);
}
}
return rst;
}
};
Extends:
1. print binary tree in vertical order
   1
        /    \
       2      3
      / \    / \
     4   5  6   7
             \   \
              8   9 
               
     
The output of print this tree vertically will be:
4
2
1 5 6
3 8
7
9
这个题目一开始看起来没有什么思路,在同一个vertical上的node感觉也没有规律,不知道怎么
标示两个Node是不是在一个vertical上,后来看了网上别人的分析才明白原来两个Node在同一个
vertical上意味着它们离某个原点(root)的距离是相同的,所以这题就转化为先求出tree上面
每个node离root的horizonal distance是多少。 最后输出的就是从最小的distance到最大的
distance每个distance上的node,在求distance的时候用一个Map存起来就可以了。
那么怎么求每个node的distance呢?从原点出发,原点的horizontal distance是0,对于每一个
parentNode而言,向左走,distance = parentNode -1, 向右走 , distance = parentNode + 1
很显然用recursion的方法preorder traverse tree就可以做了。
class Solution {
public:
//get the horizontal distance of nodes in the tree
void preorder(TreeNode* root, map<int, vector<int>> &tmap, int hd) {
 //base case
 if (root == NULL) return;
 tmap[hd].push_back(root->val);
 preorder(root->left, tmap, hd-1);
 preorder(root->right, tmap, hd+1);
}
vector<vector<int>> TopView(TreeNode* root) {
 vector<vector<int>> rst;
 //sanity check
 if (root == NULL) return rst; 
 map<int, vector<int>> tmap;
 //count the distance
 preorder(root, tmap, 0);
 //get the vector
 map<int,vector<int>> :: iterator it = tmap.begin();
 for (; it != tmap.end(); it++) {
  vector<int> tmp;
  for (int i = 0; i < (it->second).size(); i++) {
   tmp.push_back((it->second)[i]);
  }
  rst.push_back(tmp);
 }
 return rst;
}
};
AS the map is implemented by BST, the insert, find and delete operation is all O(logn),
so the time complexity is O(nlogn)
2. view the tree from top to down
 1
    /     \
   2       3
  /  \    / \
 4    5  6   7
Top view of the above binary tree is
4 2 1 3 7
        1
      /   \
    2       3
      \   
        4  
          \
            5
             \
               6
Top view of the above binary tree is
2 1 3 6
由于有上面那个vertical view of a tree的基础,这个题目就很简单了,只要在上面的那个解法里面对map的操作进行处理,只记录某个hd第一次出现的node, 就是在map里面存node之前进行判断,看是否已经有node存在里面了,如果已经有node存在里面了,那么就不继续存,
class Solution {
public:
//get the horizontal distance of nodes in the tree
void preorder(TreeNode* root, map<int, vector<int>> &tmap, int hd) {
 //base case
 if (root == NULL) return;
        if (tmap.find(hd) == tmap.end()) {
           tmap[hd].push_back(root->val);
           cout<< root->val; 
        }
 preorder(root->left, tmap, hd-1);
 preorder(root->right, tmap, hd+1);
}
int TopView(TreeNode* root) {
 vector<vector<int>> rst;
 //sanity check
 if (root == NULL) return rst; 
 map<int, vector<int>> tmap;
 //count the distance
 preorder(root, tmap, 0);
 //get the vector
 map<int,vector<int>> :: iterator it = tmap.begin();
        return 0 ;
}
};
但是上面的方法由于用了map,所以time complexity 是O(nlogn)
有没有什么方法可以使得时间复杂度降到O(n)呢?
考虑到其实map里面每次都只允许存储一个Node,所以 此时的map相当是当做set来用, 所以如果可以
用hash_set来做的话,时间复杂度是O(1)的查找。但是如何记录哪个node和它的hd的对应关系呢??
为了解决这个问题,我们可以用object来进行存储,每个object里面存储两个变量,一个node,一个hd。
C++里面的unordered_set和unordered_map就是对应java里面hash_set, hash_map, unordered_set的
对某个特定Key的查找效率比一般的set快很多, 但是unordered_set里面是不能进行排序的。
class Solution {
public://get the horizontal distance of nodes in the tree
void preorder(TreeNode* root, unordered_set<int> &uset, int hd) {
 //base case
 if (root == NULL) return;
 if (uset.find(hd) == uset.end()) {
  uset.insert(hd);
  cout<< root->val << ' ';
 }
 preorder(root->left, tmap, hd-1);
 preorder(root->right, tmap, hd+1);
}
int TopView(TreeNode* root) {
 vector<vector<int>> rst;
 //sanity check
 if (root == NULL) return rst; 
        unordered_set<int> uset;
        //count the distance
 preorder(root, uset, 0);
 //get the vector
 map<int,vector<int>> :: iterator it = tmap.begin();
        return 0 ;
}
};
以上两个都是dfs version 的代码, 其实这个题目也可以用BFS来做,如果用BFS来做的话,
每遍历一层对已经遍历过的node的hd的值进行操作,
class TreeItem {
 TreeNode* node;
 int hd;
 TreeItem(TreeNode* t1, int hd1) {
  node = t1;
  hd = hd1;
 }
};
void TopView(TreeNode* root) {
 //sanity cehck
 if (root == NULL) return;
 //BFS
 queue<TreeItem*> explore;
 unordered_set<int> uset;
 explore.push(new TreeItem(root, 0));
 while (!explore.empty()) {
  TreeItem* tmp = explore.front();
  explore.pop();
  if (uset.find(tmp->hd) == uset.end()) {
   uset.insert(hd);
   cout << (tmp->node)->val;
  }
  if (tmp->node->left) explore.push(new TreeItem(tmp->node->left, tmp->hd-1));
  if (tmp->node->right) explore.push(new TreeItem(tmp->node->right, tmp->hd+1));
 } 
 return;
}
time complexity: O(n) for the unordered_set is hash set, O(1) to find a value;
如果这个题目对于BFS的解法不定义TreeItem这个object,那么必须要使用map来存储每个node的hd,因为
在遍历到下一层的时候不知道上一层的parent的hd是多少,这样对于map来说,insert的时间复杂度是O(logn)
时间复杂度为O(nlogn). 没有上面O(n)的情况好。  
对于unordered_map: implementation 是hash_table, average insert , delete, find O(1), worset
case is O(N).
 
No comments:
Post a Comment