树相关

打印二叉树最右边的节点

给定一个二叉树,打印其每层最右边的节点的值。

#include <iostream>
#include <vector>
#include <functional>
 
using std::vector;
 
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int _val):
        val(_val), left(nullptr), right(nullptr) { }
};
 
// print the right-most node of each layer of a tree.
vector<int> PrintRightMost(TreeNode* root)
{
  // - time: O(N), where N is #TreeNodes
  // - space: O(N + logN)
  if (!root) return vector<int>(); 
  vector<vector<int>> mat;
 
  std::function<void(TreeNode*, int)> layer_travel =
    [&mat, &layer_travel](TreeNode* p, int depth)
    {
      if (p == nullptr) return;
      if (depth == (int)mat.size())
        mat.emplace_back(vector<int>());
      mat[depth].push_back(p->val);
      layer_travel(p->left, depth + 1);
      layer_travel(p->right, depth + 1);
    };
 
  vector<int> ret;
  for (auto &row : mat) ret.push_back(row.back());
  return ret;
}

二叉树的层次遍历

给定一颗二叉树,按每一层从左往右的顺序遍历。(队列的典型应用)

/*
 * This is a typical application of queue.
 * With the help of a queue, you can easily do this.
 *
 * You can also use recursion.
 */
 
#include <queue>
#include <vector>
 
using namespace std;
 
class TreeNode {
public:
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
 
class Solution {
public:
    vector<int> HierarchicalTraversal(TreeNode* root) {
        if (root == nullptr) { 
            // further error handle
            return vector<int>(); 
        }
 
        vector<int> ret;
        queue<TreeNode*> q;
        q.push(root);
 
        while(!q.empty()) {
            auto cur = q.front();
            // from left to right push the current
            // root's children to the queue
            if (cur -> left) q.push(cur -> left);
            if (cur -> right) q.push(cur -> right);
            ret.push_back(cur -> val);
            q.pop();
        }
        return ret;
    }
 
 
    /// recursive
    vector<vector<int> > layerTraverse(TreeNode* root) {
        if (root == nullptr) return ret;
        build(root, 0); 
        return ret;
    }
 
    // recursion needs a member variable
    vector<vector<int> > ret;
    void build(TreeNode* p, int depth) {
        if (p == nullptr) return;
 
        if (ret.size() == depth)
            ret.push_back(vector<int>());
        ret[depth].push_back(p -> val); // use depth to track layer
        build(p -> left, depth + 1);
        build(p -> right, depth + 1);
    }
};

递增二叉树

网易互娱2020校招正式批

给定一颗二叉树,每个节点又一个正整数权值。若一棵二叉树,每一层的节点权值之和都严格小于下一层的节点权值之和,则称这颗二叉树为递增二叉树。现在给你一颗二叉树,请判断它是否是递增二叉树。

输入描述:

输入的第一行是一个正整数T(0 < T 50)。接下来有T组样例,对于每组样例,输入的第一行是一个正整数N,表示树的节点个数(0 < N 100,节点编号为0到N-1)。接下来是N行,第k行表示编号为k的节点,输入格式为:VALUE LEFT RIGHT,其中VALUE表示其权值,是一个不超过5000的自然数;LEFT和RIGHT分别表示该节点的左孩子编号和右孩子编号。如果其不存在左孩子或右孩子,则LEFT或RIGHT为-1.

输出描述:

对于每一组样例,输出一个字符串。如果该二叉树是一颗递增树,则输出YES,否则输出NO。

样例输入:

2
8
2 -1 -1
1 5 3
4 -1 6
2 -1 -1
3 0 2
2 4 7
7 -1 -1
2 -1 -1
8
21 6 -1
52 4 -1
80 0 3
31 7 -1
21 -1 -1
59 -1 -1
50 5 -1
48 -1 1

样例输出:

YES
NO

这题最恶心的是输入格式,居然不是直接给一颗建好的二叉树的根节点,而是给数据让你自己建树。处理输入还比较麻烦,首先每个节点都有编号,得先存起来,然后一个一个构造节点,然后再连接起来,关键是连好以后,头节点在哪?还得找一下,最后的判断,实际上是二叉树的层次遍历,遍历得到一个向量,判断是否为严格单调递增即可。

上图是第一个样例画出来的二叉树,左边圆圈中对应的是节点编号,右边的数字是节点的权值。要画这棵树,首先画左边的编号之间的连接图,然后把对应编号换作节点的权值即可。那么头节点在哪呢?入度为0的就是了!

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
 
using namespace std;
 
struct TreeNode
{
  int val;
  TreeNode* left;
  TreeNode* right;
  TreeNode(int v)
    : val(v), left(nullptr), right(nullptr) {}
};
 
struct NodeInfo
{
  TreeNode* pnode;  
  int left;
  int right;
 
  NodeInfo(TreeNode* p, int l, int r):
    pnode(p), left(l), right(r) {}
};
 
// build the tree and return the root
TreeNode* BuildTree(vector<NodeInfo>& nodes)
{
  vector<int> counts(nodes.size(), 0);
  // link
  for (size_t i = 0; i != nodes.size(); ++i)
  {
    int left = nodes[i].left;
    int right = nodes[i].right;
    if (left != -1)
    {
      nodes[i].pnode->left = nodes[left].pnode;
      ++counts[left];
    }
    if (right != -1)
    {
      nodes[i].pnode->right = nodes[right].pnode;
      ++counts[right];
    }
  }
  // find root
  for (size_t i = 0; i != counts.size(); ++i)
  {
    if (counts[i] == 0)
      return nodes[i].pnode;
  }
  throw std::logic_error("no root");
}
 
// Is the tree a increasing tree?
bool IsIncrTree(TreeNode* root)
{
  if (!root) return false;
  vector<vector<int>> mat; 
 
  // tranverse the tree by layer
  std::function<void(TreeNode*, int)> layer_travel;
  layer_travel = 
    [&mat, &layer_travel](TreeNode* p, int depth) mutable
    {
      if (p == nullptr) return;
      if ((int)mat.size() == depth)
        mat.emplace_back(vector<int>());
        
      mat[depth].push_back(p->val);
      layer_travel(p->left, depth + 1);
      layer_travel(p->right, depth + 1);
    };
 
  layer_travel(root, 0);
  
  vector<int> sums;
  for (auto& row : mat)
  {
    int sum = 0;
    for (auto c : row) sum += c;
    sums.push_back(sum);
  }
 
  for (size_t i = 1; i != sums.size(); ++i)
  {
    if (sums[i-1] >= sums[i])
      return false;
  }
  return true;
}
 
int main()
{
  int num_test;
  cin >> num_test;
  
  for (int num_nodes = 0; num_test--;)
  {
    cin >> num_nodes;
    vector<NodeInfo> nodes;
    while (num_nodes--)
    {
      int v, l, r;
      cin >> v >> l >> r;
      TreeNode* p = new TreeNode(v);
      nodes.emplace_back(p, l, r);
    }
    TreeNode* root = BuildTree(nodes);
    if (IsIncrTree(root))
      cout << "YES\n";
    else
      cout << "NO\n";
 
    // memory clean
    for (auto& node : nodes)
    {
      delete node.pnode;
      node.pnode = nullptr;
    }
  } // nodes released
  return 0;
}

题九:Stern-Brocot Tree

网易雷火游戏2019校招

The Stern-Brocot tree is an infinite complete binary tree in which the verices correspond one-for-one to the positive rational numbers, whose values are ordered from the left to the right as in a search tree.

Stern-Brocot Tree

Figure above shows a part of the Stern-Brocot tree, which has the first 4 rows. The value in the node is the mediant of the left and right fractions. The mediant of two fractions A/B and C/D is defined as (A+C)/(B+D).

To construct the Stern-Brocot tree, we first define the left fraction of the root node is 0/1, and the right fraction of the root node is 1/0. So the value in the root node is the mediant of 0/1 and 1/0, which is (0+1)/(1+0)=1/1. Then the value of root node becomes the right fraction of the left child, and the left fraction of the right child. For example, the 1st node in row2 has 0/1 as its left fraction and 1/1(which is the value of its parent node) as its right fraction. So the value of the 1st node on row2 is (0+1)(1+1)=1/2. For the same reason, the value of the 2nd node in row2 is (1+1)/(1+0)=2/1. This construction progress goes on infinity. As a result, every positive rational number can be found on the Stern-Brocot tree, and can be found only once.

Give a rational nunmber in form P/Q, find the position of P/Q in the Stern-Borcot tree.

Input description: Input consists of two integers, P and Q (1P,Q 1000), which represent the rational number P/Q. We promise P and Q are relatively prime.

Output description: Output consists of two integers, R and C. R indicates the row index of P/Q in the Stern-Brocot tree, C indicates the index of P/Q in that row. Both R and C are base 1. We promise the position of P/Q is always in the first 12 rows of the Stern-Brocot tree, which means R12.

Sample input:

5 3

Sample output:

4 6

Idea: tree structure is natural for recursion.

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
 
using namespace std;
 
// build Rat abstraction
typedef std::pair<int, int> Rat;  // the rational numbers
 
Rat operator+(const Rat& lhs, const Rat& rhs)
{
  // 事实上这里需要化简使得分子分母互素
  // 不过下面我判断等于的时候是交叉相乘判断的,故不影响结果
  return std::make_pair(
      lhs.first + rhs.first,
      lhs.second + rhs.second);
}
 
bool operator<(const Rat& lhs, const Rat& rhs)
{
  return (lhs.first * rhs.second)
       < (rhs.first * lhs.second);
}
 
bool operator>(const Rat& lhs, const Rat& rhs)
{
  return !(lhs < rhs);
}
 
bool operator==(const Rat& lhs, const Rat& rhs)
{
  return (lhs.first * rhs.second)
      == (rhs.first * lhs.second);
}
 
void Printer(const Rat& r)
{
  cout << r.first << "/" << r.second << endl;
}
// done
 
struct SBTreeNode
{
  Rat LF; // left fraction
  Rat val;
  Rat RF; // right fraction
  SBTreeNode(Rat l, Rat v, Rat r)
    : LF(l), val(v), RF(r)
  {
  }
};
 
/// search the SBTree for target, return the row and col index
void SearchOnTree(
    SBTreeNode& root, const Rat& target, int* prow, int* pcol)
{
  // base case
  if (target == root.val) return;
  
  // 可以看到Stern-Brocot树具有二叉排序树的特征
  // left-child < parent < right-child
  if (target < root.val)
  { // go left
    root.RF = root.val;
    root.val = root.val + root.LF;
    ++(*prow);
    *pcol = (*pcol) * 2 - 1;
    SearchOnTree(root, target, prow, pcol);
  }
  else if (target > root.val)
  { // go right
    root.LF = root.val;
    root.val = root.val + root.RF;
    ++(*prow);
    (*pcol) *= 2; // 注意列索引的增量,仔细看规律
    SearchOnTree(root, target, prow, pcol);
  }
}
 
int main()
{
  Rat query;
  cin >> query.first >> query.second;
  SBTreeNode root(Rat(0,1), Rat(1,1), Rat(1,0));
  // root.RF = root.val;
  // root.val = root.val + root.LF;
  // cout << "LF "; Printer(root.LF);
  // cout << "val "; Printer(root.val);
  // cout << "RF "; Printer(root.RF);
 
  int row = 1, col = 1;
  SearchOnTree(root, query, &row, &col);
  cout << row << " " << col << endl;
  return 0;
}