# 数据结构丨二叉树

## 树的遍历

### 二叉树的前序遍历

输入: [1,null,2,3]
1
\
2
/
3



#include <iostream>
#include <vector>
#include <stack>

using namespace std;

struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x):val(x),left(NULL),right(NULL){}
};

// Recursive
// Time Complexity: O(n), n is the node number in the tree
// Space Complexity: O(h), h is the height of the tree
class SolutionA{
public:
vector<int> preorderTraversal(TreeNode* root){
vector<int> res;
preorderTraversal(root, res);
return res;
}
private:
void preorderTraversal(TreeNode* node, vector<int> &res){
if(node){
res.push_back(node->val);
preorderTraversal(node->left, res);
preorderTraversal(node->right, res);
}
}
};

// Classic Non-Recursive algorithm for preorder traversal
// Time Complexity: O(n), n is the node number in the tree
// Space Complexity: O(h), h is the height of the tree
class SolutionB{
public:
vector<int> preorderTraversal(TreeNode* root){
vector<int> res;
if(root == NULL);
return res;

stack<TreeNode*> stack;
stack.push(root);
while(!stack.empty()){
TreeNode* curNode = stack.top();
stack.pop();
res.push_back(curNode->val);

if(curNode->right)
stack.push(curNode->right);
if(curNode->left)
stack.push(curNode->left);
}
return res;
}
}
int main(){
return 0;
}


### 二叉树的中序遍历

输入: [1,null,2,3]
1
\
2
/
3



#include <iostream>
#include <vector>
#include <stack>

using namespace std;

/// Definition for a binary tree node.
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x):val(x), left(NULL), right(NULL){}
};

// Recursive
// Time Complexity: O(n), n is the node number in the tree
// Space Complexity: O(h), h is the height of the tree
class SolutionA{
public:
vector<int> inorderTraversal(TreeNode* root){
vector<int> res;
__inorderTraversal(root, res);
return res;
}
private:
void __inorderTraversal(TreeNode* node, vector<int>& res){
if(node){
__inorderTraversal(node->left, res);
res.push_back(node->val);
__inorderTraversal(node->right, res);
}
}
};

// Classic Non-Recursive algorithm for inorder traversal
// Time Complexity: O(n), n is the node number in the tree
// Space Complexity: O(h), h is the height of the tree
class SolutionB{
public:
vector<int> inorderTraversal(TreeNode* root){
vector<int> res;
if(root == NULL)
return res;

stack<TreeNode*> stack;
TreeNode* cur = root;
while(cur != NULL || !stack.empty()){
//先到达左下端
while(cur != NULL){
stack.push(cur);
cur = cur->left;
}
cur = stack.top();
stack.pop();
res.push_back(cur->val);
cur = cur->right;
}
return res;
}
};


### 二叉树的后序遍历

输入: [1,null,2,3]
1
\
2
/
3



#include <iostream>
#include <vector>
#include <stack>

using namespace std;

struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x): val(x), left(NULL), right(NULL){}
};

// Recursive
// Time Complexity: O(n), n is the node number in the tree
// Space Complexity: O(h), h is the height of the tree
class SolutionA{
public:
vector<int> postorderTraversal(TreeNode* root){
vector<int> res;
__postorderTraversal(root, res);
return res;
}
private:
void __postorderTraversal(TreeNode* node, vector<int> &res){
if(node){
__postorderTraversal(node->left, res);
__postorderTraversal(node->right, res);
res.push_back(node->val);
}
}
};

// Classic Non-Recursive
// Using a pre pointer to record the last visted node
//
// Time Complexity: O(n)
// Space Complexity: O(h)
class SolutionB{
public:
vector<int> postorderTraversal(TreeNode* root){
vector<int> res;
if(root == NULL)
return res;
stack<TreeNode*> stack;
TreeNode* pre = NULL;
TreeNode* cur = root;

while(cur != NULL || !stack.empty()){
//到达最左下端
while(cur != NULL){
stack.push(cur);
cur = cur->left;
}
cur = stack.top();
stack.pop();

//确保该节点没有右子树或者右子树已遍历过
if(cur->right == NULL || pre == cur->right){
res.push_back(cur->val);
pre = cur;
cur = NULL;
}
else{
stack.push(cur);
cur = cur->right;
}
}
return res;
}
};


### 层次遍历-介绍

广度优先搜索是一种广泛运用在树或图这类数据结构中，遍历或搜索的算法。 该算法从一个根节点开始，首先访问节点本身。 然后遍历它的相邻节点，其次遍历它的二级邻节点、三级邻节点，以此类推。

### 二叉树的层次遍历

    3
/ \
9  20
/  \
15   7


[
[3],
[9,20],
[15,7]
]

#include <iostream>
#include <vector>
#include <queue>
#include <cassert>

using namespace std;

struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x): val(x), left(NULL), right(NULL){}
};

/// BFS
/// Time Complexity: O(n), where n is the number of nodes in the tree
/// Space Complexity: O(n)
class Solution{
public:
vector<vector<int>> levelOrder(TreeNode* root){
vector<vector<int>> res;
if(root == NULL)
return res;

queue<pair<TreeNode*, int>> q;
q.push(make_pair(root, 0));

while(!q.empty()){
TreeNode* node = q.front().first;
int level = q.front().second;
q.pop();

if(level == res.size())
res.push_back(vector<int>());
assert(level <res.size());

res[level].push_back(node->val);
if(node->left)
q.push(make_pair(node->left, level+1));
if(node->right)
q.push(make_pair(node->right, level+1));
}
return res;
}
};


## 运用递归解决问题

### 运用递归解决树的问题

“自顶向下” 的解决方案

“自顶向下” 意味着在每个递归层级，我们将首先访问节点来计算一些值，并在递归调用函数时将这些值传递到子节点。 所以 “自顶向下” 的解决方案可以被认为是一种前序遍历。 具体来说，递归函数 top_down(root, params) 的原理是这样的：

1. return specific value for null node
2. update the answer if needed                      // anwer <-- params
3. left_ans = top_down(root.left, left_params)      // left_params <-- root.val, params
4. right_ans = top_down(root.right, right_params)   // right_params <-- root.val, params
5. return the answer if needed


1. return if root is null
2. if root is a leaf node:
4. maximum_depth(root.left, depth + 1)      // call the function recursively for left child
5. maximum_depth(root.right, depth + 1)     // call the function recursively for right child


“自底向上” 的解决方案

“自底向上” 是另一种递归方法。 在每个递归层次上，我们首先对所有子节点递归地调用函数，然后根据返回值和根节点本身的值得到答案。 这个过程可以看作是后序遍历的一种。 通常， “自底向上” 的递归函数 bottom_up(root) 为如下所示：

1. return specific value for null node
2. left_ans = bottom_up(root.left)          // call function recursively for left child
3. right_ans = bottom_up(root.right)        // call function recursively for right child


1. return 0 if root is null                 // return 0 for null node
2. left_depth = maximum_depth(root.left)
3. right_depth = maximum_depth(root.right)
4. return max(left_depth, right_depth) + 1  // return depth of the subtree rooted at root


1. 你能确定一些参数，从该节点自身解决出发寻找答案吗？
2. 你可以使用这些参数和节点本身的值来决定什么应该是传递给它子节点的参数吗？

### 二叉树的最大深度

    3
/ \
9  20
/  \
15   7


#include <iostream>

using namespace std;

struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x): val(x), left(NULL), right(NULL){}
};

/// Recursive
/// Time Complexity: O(n), where n is the nodes' number in the tree
/// Space Complexity: O(h), where h is the height of the tree
class Solution{
public:
int maxDepth(TreeNode* root){
if(root == NULL)
return 0;
return 1+max(maxDepth(root->left), maxDepth(root->right));
}
};

int main(){
return 0;
}


### 对称二叉树

    1
/ \
2   2
/ \ / \
3  4 4  3


    1
/ \
2   2
\   \
3    3


#include <iostream>
#include <queue>

using namespace std;

/// Definition for a binary tree node.
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

/// Recursive
/// No need to revert one child tree
/// See if the two child trees of the root are mirror directly
///
/// Time Complexity: O(n)
/// Space Complexity: O(h)
class SolutionA
{
public:
bool isSymmetric(TreeNode *root)
{
if (root == NULL)
return true;
return is_mirror(root, root);
}

private:
bool is_mirror(TreeNode *root1, TreeNode *root2)
{
if (root1 == NULL && root2 == NULL)
return true;

if (root1 == NULL || root2 == NULL)
return false;

if (root1->val != root2->val)
return false;

return is_mirror(root1->left, root2->right) &&
is_mirror(root1->right, root2->left);
}
};

/// Non-Recursive
/// Using one queues to level traverse the root in different directions
///
/// Time Complexity: O(n)
/// Space Complexity: O(n)
class SolutionB{
public:
bool isSymmetric(TreeNode* root){
if(root == NULL)
return true;

queue<TreeNode*> q;
q.push(root);
q.push(root);
while(!q.empty()){
TreeNode* node1 = q.front();
q.pop();

TreeNode* node2 = q.front();
q.pop();

if(node1 == NULL && node2 == NULL)
continue;

if(node1 == NULL || node2 == NULL)
return false;

if(node1->val != node2->val)
return false;

q.push(node1->left);
q.push(node2->right);
q.push(node1->right);
q.push(node2->left);

}
return true;
}
};


### 路径总和

              5
/ \
4   8
/   / \
11  13  4
/  \      \
7    2      1


#include <iostream>

using namespace std;

/// Definition for a binary tree node.
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

/// Recursive
/// Time Complexity: O(n), where n is the nodes' number of the tree
/// Space Complexity: O(h), where h is the height of the tree
class Solution
{
public:
bool hasPathSum(TreeNode *root, int sum)
{
if (root == NULL)
return false;
if (root->left == NULL && root->right == NULL)
return sum == root->val;

return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val);
}
};

int main(){
return 0;
}


## 总结

### 从中序与后序遍历序列构造二叉树

中序遍历 inorder = [9,3,15,20,7]



    3
/ \
9  20
/  \
15   7

#include <iostream>
#include <vector>
#include <cassert>
#include <algorithm>

using namespace std;

/// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

/// Recursive
/// Time Complexity: O(n*h) where n is the num of node in th tree
///                         and h is the height of the tree
/// Space Complexity: O(h)
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return buildTree(inorder, 0, inorder.size(), postorder, 0, postorder.size());
}

private:
TreeNode* buildTree(vector<int>& inorder, int inorderL, int inorderR,
vector<int>& postorder, int postorderL, int postorderR){

if(inorderL >= inorderR){
assert(postorderL >= postorderR);
return NULL;
}

if(inorderL + 1 == inorderR){
assert(postorderL + 1 == postorderR);
return new TreeNode(inorder[inorderL]);
}

TreeNode* root = new TreeNode(postorder[postorderR - 1]);
int rootPos = find(inorder.begin() + inorderL, inorder.begin() + inorderR, root->val) - inorder.begin();
assert(inorderL <= rootPos && rootPos < inorderR);

int lsize = rootPos - inorderL;
int rsize = inorderR - (rootPos + 1);
root->left = buildTree(inorder, inorderL, inorderL + lsize, postorder, postorderL, postorderL + lsize);
root->right = buildTree(inorder, rootPos + 1, inorderR, postorder, postorderL + lsize, postorderR - 1);
return root;
}
};

int main() {

vector<int> inorder = {9,3,15,20,7};
vector<int> postorder = {9,15,7,20,3};
TreeNode* root = Solution().buildTree(inorder, postorder);
printf("ok");

return 0;
}


### 从前序与中序遍历序列构造二叉树

前序遍历 preorder = [3,9,20,15,7]



    3
/ \
9  20
/  \
15   7

#include <iostream>
#include <vector>
#include <cassert>
#include <algorithm>

using namespace std;

/// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

/// Recursive
/// Time Complexity: O(n*h) where n is the num of node in th tree
///                         and h is the height of the tree
/// Space Complexity: O(h)
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return buildTree(preorder, 0, preorder.size(), inorder, 0, inorder.size());
}

private:
TreeNode* buildTree(const vector<int>& preorder, int preorderL, int preorderR,
const vector<int>& inorder, int inorderL, int inorderR){

if(inorderL >= inorderR){
assert(preorderL >= preorderR);
return NULL;
}

if(inorderL + 1 == inorderR){
assert(preorderL + 1 == preorderR);
return new TreeNode(inorder[inorderL]);
}

TreeNode* root = new TreeNode(preorder[preorderL]); //就变化了这一行
int rootPos = find(inorder.begin() + inorderL, inorder.begin() + inorderR, root->val) - inorder.begin();
assert(rootPos >= inorderL && rootPos < inorderR);

int lsize = rootPos - inorderL;
int rsize = inorderR - (rootPos + 1);
root->left = buildTree(preorder, preorderL + 1, preorderL + 1 + lsize, inorder, inorderL, rootPos);
root->right = buildTree(preorder, preorderL + 1 + lsize, preorderR, inorder, rootPos + 1, inorderR);
return root;
}
};

int main() {

vector<int> preorder = {3, 9, 20, 15, 7};
vector<int> inorder = {9,3,15,20,7};
TreeNode* root = Solution().buildTree(preorder, inorder);
printf("ok");

return 0;
}


### 填充每个节点的下一个右侧节点指针

struct Node {
int val;
Node *left;
Node *right;
Node *next;
}


输入：{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":null,"right":null,"val":4},"next":null,"right":{"$id":"4","left":null,"next":null,"right":null,"val":5},"val":2},"next":null,"right":{"$id":"5","left":{"$id":"6","left":null,"next":null,"right":null,"val":6},"next":null,"right":{"$id":"7","left":null,"next":null,"right":null,"val":7},"val":3},"val":1} 输出：{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":{"$id":"4","left":null,"next":{"$id":"5","left":null,"next":{"$id":"6","left":null,"next":null,"right":null,"val":7},"right":null,"val":6},"right":null,"val":5},"right":null,"val":4},"next":{"$id":"7","left":{"$ref":"5"},"next":null,"right":{"$ref":"6"},"val":3},"right":{"$ref":"4"},"val":2},"next":null,"right":{"$ref":"7"},"val":1}



• 你只能使用常量级额外空间。
• 使用递归解题也符合要求，本题中递归程序占用的栈空间不算做额外的空间复杂度。
#include <iostream>
#include <queue>
#include <cassert>

using namespace std;

/// Using queue for BFS
/// Time Complexity: O(n)
/// Space Compelxity: O(n)

/// Definition for binary tree with next pointer.
int val;
TreeLinkNode(int x): val(x), left(NULL), right(NULL), next(NULL){}
};

//层次遍历中前一个节点的next指向后一个节点
class SolutionA{
public:
if(!root) return;

q.push(root);
int level = 0;
while(!q.empty()){
//移动几位就是二的几次方，跟每层的节点数目相对应
int n = (1 << level);
while(n --){    //遍历每一个节点
q.pop();
if(n)   //每层的最后一个节点不作处理
cur->next = q.front();
if(cur->left){
q.push(cur->left);
assert(cur->right);
q.push(cur->right);
}
}
level ++;
}
}
};

/// DFS
/// Time Complexity: O(n)
/// Space Compelxity: O(logn)

/// Definition for binary tree with next pointer.
class SolutionB{
public:
if(!root || !root->left) return;
dfs(root->left, root->right);   //所有左节点的next指向右节点

connect(root->left);
connect(root->right);
}
private:
if(l){
l->next = r;
dfs(l->right, r->left); //所有右节点的next指向左节点
}
}
};

/// BFS without queue
/// We can traverse the upper level in a linked list way to connect the lower level
/// Actually, the upper linked list is our queue :-)
///
/// Time Complexity: O(n)
/// Space Compelxity: O(1)

/// Definition for binary tree with next pointer.
class SolutionC{
public:
if(!root) return;

while(root->left){
while(p){
cur->next = p->next;
cur = cur->next;

cur->next = p->right;
cur = cur->next;

p = p->next;
}
}
}
}


### 填充每个节点的下一个右侧节点指针 II

struct Node {
int val;
Node *left;
Node *right;
Node *next;
}


输入：{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":null,"right":null,"val":4},"next":null,"right":{"$id":"4","left":null,"next":null,"right":null,"val":5},"val":2},"next":null,"right":{"$id":"5","left":null,"next":null,"right":{"$id":"6","left":null,"next":null,"right":null,"val":7},"val":3},"val":1}



• 你只能使用常量级额外空间。
• 使用递归解题也符合要求，本题中递归程序占用的栈空间不算做额外的空间复杂度。
#include <iostream>
#include <queue>

using namespace std;

/// Using BFS
/// Time Complexity: O(n)
/// Space Complexity: O(n)

/// Definition for binary tree with next pointer.
struct Node{
int val;
Node* left, *right, *next;
Node(int x): val(x), left(NULL), right(NULL), next(NULL) {}
};

//该解法和3.3的解法没有差异
class Solution{
public:
Node* connect(Node* root){
if(!root)
return NULL;

queue<Node*> q;
q.push(root);
int level_num = 1;
while(!q.empty()){
int new_level_num = 0;
for(int i=0; i<level_num; i++){
Node* node = q.front();
q.pop();
node->next = (i == level_num - 1 ? NULL : q.front());//用来判断是否为最后一个节点

if(node->left){
q.push(node->left);
new_level_num ++;
}
if(node->right){
q.push(node->right);
new_level_num ++;
}
}
level_num = new_level_num;  //用来对下一层的节点进行计数
}
return root;
}
};



### 二叉树的最近公共祖先

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1



输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4



• 所有节点的值都是唯一的。
• p、q 为不同节点且均存在于给定的二叉树中。

#include <iostream>
#include <cassert>

using namespace std;

/// Recursion implementation
/// Time Complexity: O(n)
/// Space Complexity: O(1)

///Definition for a binary tree node.
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x): val(x), left(NULL), right(NULL){}
};

class Solution{
public:
// 在root中寻找p和q
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q){
//底部的基本情况
if(root == NULL)    // 节点为空
return root;
if(root == p || root == q)     // 节点不为空，判断是否找到，无需关心是否为叶子节点
return root;

TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);

if(left != NULL && right != NULL)   //且左右节点都是目标，返回自身
return root;

//自底向上，最后返回的，自身为目标节点，且另一个目标节点在其之下。
if(left != NULL)    //左节点非空
return left;

if(right != NULL)   //右节点非空
return right;

return NULL;    //左右节点都为空
}
};


### 二叉树的序列化与反序列化

你可以将以下二叉树：

1
/ \
2   3
/ \
4   5



#include <iostream>
#include <vector>
#include <queue>
#include <cassert>

using namespace std;

/// BFS
/// Time Complexity: O(n)
/// Space Complexity: O(n)

/// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Codec{
public:
//Encodes a tree to a single string.
string serialize(TreeNode* root){
if(root)
return "[null]";

string ret = "[";

queue<TreeNode*> q;
q.push(root);
ret += to_string(root->val);
while(!q.empty()){
TreeNode* cur = q.front();
q.pop();

if(cur->left){
ret += "," + to_string(cur->left->val);
q.push(cur->left);
}
else
ret += ",null";

if(cur->right){
ret += "," + to_string(cur->right->val);
q.push(cur->right);
}
else
ret += ",null";
}
return ret + "]";
}

// Decodes your encoded data to tree.
TreeNode* deserialize(string data){
vector<string> vec = get_vector(data);

if(vec.size()==0 || (vec.size() == 1 && vec[0]=="nulll"))
return NULL;

TreeNode* root = new TreeNode(atoi(vec[0].c_str()));
queue<TreeNode*> q;
q.push(root);
int index = 1;
while(!q.empty()){
TreeNode* cur = q.front();
q.pop();

assert(vec.size() - index >= 2);
if(vec[index] != "null"){
cur->left = new TreeNode(atoi(vec[index].c_str()));
q.push(cur->left);
}
index ++;

if(vec[index] != "null"){
cur->right = new TreeNode(atoi(vec[index].c_str()));
q.push(cur->right);
}
index ++;
}
return root;
}
private:
vector<string> get_vector(const string& data){
string s = data.substr(1, data.size() -2) + ",";

vector<string> res;
int i = 0;
while(i < s.size()){
int comma = s.find(',', i);
res.push_back(s.substr(i, comma - i));
i = comma + 1;
}
return res;
}
};

int main() {

TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->right->left = new TreeNode(4);
root->right->right = new TreeNode(5);

string s = Codec().serialize(root);
cout << s << endl;

TreeNode* x = Codec().deserialize(s);
cout << Codec().serialize(x) << endl;

return 0;
}

posted @ 2019-07-14 18:45  vincent1997  阅读(822)  评论(0编辑  收藏