5. 树

作者: superlj666 | 来源:发表于2017-04-15 11:29 被阅读0次

树相关题目套路:
  • 先序
  • 中序
  • 后序
  • DFS其他遍历方式(如右左根)
  • 层序遍历
if (!root) xxx; //应对只有左子树或只有右子树的情况
if (!root->left && !root->right) xxx;//应对叶子节点的情况

144. Binary Tree Preorder Traversal
Given a binary tree, return the preorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},
   1
    \
     2
    /
   3
return [1,2,3].
返回先序遍历的结果。其中使用迭代时要用栈保存应该的遍历顺序。访问栈顶元素,栈顶的right节点先压入栈中,栈顶的left节点再压入栈中。
// 递归
vector<int> preorderTraversal(TreeNode* root) {
    vector<int> res;
    preorder(root, res);
    return res;
}
void preorder(TreeNode *root, vector<int> &res) {
    if (!root) return;
    res.push_back(root->val);
    preorder(root->left, res);
    preorder(root->right, res);
}

// 迭代
vector<int> preorderTraversal(TreeNode* root) {
    vector<int> res;
    if (!root) return res;
    stack<TreeNode*> nodeStack;
    nodeStack.push(root);
    while (!nodeStack.empty()) {
        TreeNode* tmp = nodeStack.top();
        nodeStack.pop();
        res.push_back(tmp->val);
        if (tmp->right) nodeStack.push(tmp->right);
        if (tmp->left) nodeStack.push(tmp->left);
    }
    return res;
}

94. Binary Tree Inorder Traversal
Given a binary tree, return the inorder traversal of its nodes' values.

For example:
Given binary tree [1,null,2,3],
   1
    \
     2
    /
   3
return [1,3,2].
返回中序遍历的结果。其中使用迭代时要用栈保存应该的遍历顺序。如果没访问过栈顶的左节点,将左节点压入栈中;其他情况时,栈顶元素加入结果,并把栈顶元素的右节点压入栈中。
// 递归
vector<int> inorderTraversal(TreeNode* root) {
    vector<int> res;
    inorder(root, res);
    return res;
}
void inorder(TreeNode *root, vector<int> &res) {
    if(!root) return;
    
    inorder(root->left, res);
    res.push_back(root->val);
    inorder(root->right, res);
}
// 迭代
vector<int> inorderTraversal(TreeNode* root) {
    vector<int> res;
    if (!root) return res;
    stack<TreeNode*> nodeStack;
    unordered_map<TreeNode*, bool> visited;
    nodeStack.push(root);
    while (!nodeStack.empty()) {
        TreeNode* tmp = nodeStack.top();
        if (tmp->left && !visited[tmp]) {
            nodeStack.push(tmp->left);
            visited[tmp] = true;
        } else {
            res.push_back(tmp->val);
            nodeStack.pop();
            if (tmp->right) nodeStack.push(tmp->right);
        }
    }
    return res;
}

145. Binary Tree Postorder Traversal
Given a binary tree, return the postorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},
   1
    \
     2
    /
   3
return [3,2,1].
返回后序遍历的结果。
// 递归
vector<int> postorderTraversal(TreeNode *root) {
    vector<int> res;
    postorder(root, res);
    return res;
}
void postorder(TreeNode* root, vector<int> &res) {
    if (!root) return;
    postorder(root->left, res);
    postorder(root->right, res);
    res.push_back(root->val);
}

// 迭代1,使用类似先序遍历的方式,使用中-右-左的的入栈顺序,加入结果的顺序为逆序,即左-右-中的顺序
vector<int> postorderTraversal(TreeNode *root) {
    vector<int> res;
    if (!root) return res;
    stack<TreeNode*> nodeStack;
    nodeStack.push(root);
    
    while (!nodeStack.empty()) {
        TreeNode *tmp = nodeStack.top();
        nodeStack.pop();
        
        res.insert(res.begin(), tmp->val);
        if (tmp->left) nodeStack.push(tmp->left);
        if (tmp->right) nodeStack.push(tmp->right);
    }
    return res;
}

// 迭代2,使用类似中序遍历的方式,记录每个点是否被访问过
vector<int> postorderTraversal(TreeNode *root) {
    vector<int> res;
    if (!root) return res;
    stack<TreeNode*> nodeStack;
    unordered_map<TreeNode*, bool> visited;
    nodeStack.push(root);
    
    while (!nodeStack.empty()) {
        TreeNode *tmp = nodeStack.top();
        if (tmp->left && !visited[tmp->left]) {
            nodeStack.push(tmp->left);
            visited[tmp->left] = true;
        } else if (tmp->right && !visited[tmp->right]) {
            nodeStack.push(tmp->right);
            visited[tmp->right] = true;
        } else {
            nodeStack.pop();
            res.push_back(tmp->val);
        }
    }
    return res;
}

98. Validate Binary Search Tree
验证二叉搜索树是否合法。先序遍历。利用了根节点的值,比左子树所有节点都大,比右子树所有节点都小的性质。
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        return helper(root, LONG_MIN, LONG_MAX);
    }
    
    bool helper(TreeNode* root, long minVal, long maxVal) {
        if (!root) return true;
        if (root->val >= maxVal || root->val <= minVal) return false;
        return helper(root->left, minVal, root->val) && helper(root->right, root->val, maxVal);
    }
};

109. Convert Sorted List to Binary Search Tree
根据有序链表生成平衡二叉搜索树。先序遍历,找出链表中点作为root节点。
class Solution {
public:
    TreeNode* sortedListToBST(ListNode* head) {
        if (!head) return NULL;
        ListNode preHead = ListNode(0);
        preHead.next = head;
        ListNode *twoStep = head, *mid = head, *preMid = &preHead;
        while (mid && twoStep && twoStep->next) {
            preMid = preMid->next;
            mid = mid->next;
            twoStep = twoStep->next->next;
        }
        
        preMid->next = NULL;
        
        TreeNode *node = new TreeNode(mid->val);
        node->left = sortedListToBST(preHead.next);
        node->right = sortedListToBST(mid->next);
        return node;
    }
    
};

100. Same Tree
Given two binary trees, write a function to check if they are equal or not.
Two binary trees are considered equal if they are structurally identical and the nodes have the same value.
比较2棵树是否相同,dfs,先序遍历且左右子树同时遍历。
bool isSameTree(TreeNode* p, TreeNode* q) {
    if (!p && !q) return true;
    if (!p || !q) return false;
    return p->val == q->val && isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

101. Symmetric Tree
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).

For example, this binary tree [1,2,2,3,4,4,3] is symmetric:

    1
   / \
  2   2
 / \ / \
3  4 4  3
But the following [1,2,2,null,3,null,3] is not:
    1
   / \
  2   2
   \   \
   3    3
Note:
Bonus points if you could solve it both recursively and iteratively.
审题要仔细,这个是要求是否是镜像二叉树,即是左右对称的。
bool isSymmetric(TreeNode* root) {
    if (!root) return true;
    return comp(root->left, root->right);
}
bool comp(TreeNode* p, TreeNode* q) {
    if (!p && !q) return true;
    if (!p || !q) return false;
    return p->val == q->val && comp(p->left, q->right) && comp(p->right, q->left);
}

105. Construct Binary Tree from Preorder and Inorder Traversal
Given preorder and inorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.
节点值不重复,根据先序遍历结果和中序遍历结果构造出树。思路很清晰,先序第一个为root,再到中序找root节点,左边的为左子树,右边的为右子树。(实现起来有点恶心)
已知后序和中序构造树的情况差不多,后序的最后一个节点为root节点。
要确定树的结果必须有中序,如果只有先序和后序是无法区分左右子树的。
TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
    return create(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1);
}
TreeNode* create(vector<int>& preorder, vector<int>& inorder, int ps, int pe, int is, int ie){
    if(ps > pe){
        return nullptr;
    }
    TreeNode* node = new TreeNode(preorder[ps]);
    int pos;
    for(int i = is; i <= ie; i++){
        if(inorder[i] == node->val){
            pos = i;
            break;
        }
    }
    node->left = create(preorder, inorder, ps + 1, ps + pos - is, is, pos - 1);
    node->right = create(preorder, inorder, pe - ie + pos + 1, pe, pos + 1, ie);
    return node;
}

113. Path Sum II
Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.

For example:
Given the below binary tree and sum = 22,
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1
return
[
   [5,4,11,2],
   [5,8,4,5]
]
求全部从根节点到叶子节点val之和为sum的情况。
vector<vector<int>> pathSum(TreeNode* root, int sum) {
    vector<vector<int>> res;
    if (!root) return res;
    pathSum(root, sum, res, {});
    return res;
}
void pathSum(TreeNode* root, int sum, vector<vector<int>> &res, vector<int> cur) {
    if (!root) return;
    
    sum -= root->val;
    cur.push_back(root->val);
    if (!root->left && !root->right) {
        if (!sum) res.push_back(cur);
        return;
    }
    
    pathSum(root->left, sum, res, cur);
    pathSum(root->right, sum, res, cur);
}

129. Sum Root to Leaf Numbers
Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.
An example is the root-to-leaf path 1->2->3 which represents the number 123.
Find the total sum of all root-to-leaf numbers.
For example,
    1
   / \
  2   3
The root-to-leaf path 1->2 represents the number 12.
The root-to-leaf path 1->3 represents the number 13.

Return the sum = 12 + 13 = 25.
返回从根节点到叶子节点代表数值的和。注意preorder中的对root为空时,返回0。此时对应的情况为只是存在一边子树的情况。
int sumNumbers(TreeNode* root) {
    if (!root) return 0;
    return preorder(root, 0);
}
int preorder(TreeNode* root, int val) {
    if (!root) return 0;
    
    val = val*10 + root->val;
    if (!root->left && !root->right) return val;
    return preorder(root->left, val) + preorder(root->right, val);
}

99. Recover Binary Search Tree
Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?
利用了二叉搜索树的有序特点,中序遍历会得到拍好序的结果。
6, 3, 4, 5, 2
We compare each node with its next one and we can find out that 6 is the first element to swap because 6 > 3 and 2 is the second element to swap because 2 < 5.
要注意遍历的left、right的取值,left取prev,right取root。
class Solution {
public:
    void recoverTree(TreeNode* root) {
        inorder(root);
        if (left && right) {
            swap(left->val, right->val);
        }
    }
    
    void inorder(TreeNode* root) {
        if (!root) return;
    
        inorder(root->left);
        if (!left && prev->val >= root->val) left = prev;
        if (left && prev->val >= root->val) right = root;
        prev = root;
        inorder(root->right);
    }
private:
    TreeNode* left = NULL;
    TreeNode* right = NULL;
    TreeNode* prev = new TreeNode(INT_MIN);
};

110. Balanced Binary Tree
Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
求二叉树是否是平衡二叉树,左右深度差不超过1
// 方法1:时间复杂度O(nlogn),每次遍历求该点的深度。
int getDepth(TreeNode* root) {
    if (!root) return 0;
    return max(getDepth(root->left), getDepth(root->right)) + 1;
}
bool isBalanced(TreeNode* root) {
    if (!root) return true;
    
    int left = getDepth(root->left);
    int right = getDepth(root->right);
    return abs(left - right) <= 1 && isBalanced(root->left) && isBalanced(root->right);
}

// 方法2:时间复杂度O(n),返回值为int,用-1来标记不成功。
int getDFSDepth(TreeNode* root) {
    if (!root) return 0;
    
    int left = getDFSDepth(root->left);
    if (left == -1) return -1;
    int right = getDFSDepth(root->right);
    if (right == -1) return -1;
    
    if (abs(left-right) > 1) return -1;
    
    return max(left, right) + 1;
}
bool isBalanced(TreeNode* root) {
    return getDFSDepth(root) != -1;
}

124. Binary Tree Maximum Path Sum
Given a binary tree, find the maximum path sum.

For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.

For example:
Given the below binary tree,

       1
      / \
     2   3
Return 6.
这道题目的意思是求连城一条线的最大和(因为可能有节点值为负,所以可能是中断的)。
每个节点为root的情况为,maxSum = max(maxSum, left + right + node->val)。其中left、right均大于等于0。
int maxPathSum(TreeNode* root) {
    int maxValue = INT_MIN;
    maxPathDown(root, maxValue);
    return maxValue;
}
int maxPathDown(TreeNode* node, int &maxValue) {
    if (node == nullptr) return 0;
    int left = max(0, maxPathDown(node->left, maxValue));
    int right = max(0, maxPathDown(node->right, maxValue));
    maxValue = max(maxValue, left + right + node->val);
    return max(left, right) + node->val;
}

114. Flatten Binary Tree to Linked List
Given a binary tree, flatten it to a linked list in-place.

For example,
Given

         1
        / \
       2   5
      / \   \
     3   4   6
The flattened tree should look like:
   1
    \
     2
      \
       3
        \
         4
          \
           5
            \
             6
将二叉树按照先序遍历的顺序重新构造成链表。根左右=>右左根,从结果序列的后面往前遍历,记录上一个并将right指向上一个。
class Solution {
public:
    void flatten(TreeNode* root) {
        if (!root) return;
        flatten(root->right);
        flatten(root->left);
        root->right = prev;
        root->left = NULL;
        
        prev = root;
    }
private:
    TreeNode* prev = NULL;
};

102. Binary Tree Level Order Traversal
Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

For example:
Given binary tree [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
return its level order traversal as:
[
  [3],
  [9,20],
  [15,7]
]
从顶到底,从左到右依次输出节点值。和层序遍历的主要区别是,记录每层节点个数,依次取出。
vector<vector<int>> levelOrder(TreeNode* root) {
    vector<vector<int>> res;
    if (!root) return res;
    queue<TreeNode*> nodeQueue;
    nodeQueue.push(root);
    
    while (!nodeQueue.empty()) {
        auto level = nodeQueue.size();
        res.push_back(vector<int>());
        for (auto i = 0; i < level; ++i) {
            TreeNode* node = nodeQueue.front();
            nodeQueue.pop();
            
            res[res.size() - 1].push_back(node->val);
            if (node->left) nodeQueue.push(node->left);
            if (node->right) nodeQueue.push(node->right);
        }
        
    }
    return res;
}

103. Binary Tree Zigzag Level Order Traversal
Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).

For example:
Given binary tree [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
return its zigzag level order traversal as:
[
  [3],
  [20,9],
  [15,7]
]
BFS。使用队列记录遍历过的点,每次循环更新队列中节点为树某一层节点。需要注意每次循环开始时,记录当前队列节点个数,本次循环取出全部该个数节点。
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
    if (!root) return vector<vector<int>>();
    
    vector<vector<int>> res;
    bool left2right = true;
    queue<TreeNode*> nodeQueue;
    nodeQueue.push(root);
    while (!nodeQueue.empty()) {
        int queueSize = nodeQueue.size();
        vector<int> row(queueSize);
        for (int i = 0; i < queueSize; ++i) {
            TreeNode *node = nodeQueue.front();
            nodeQueue.pop();
            
            int index = left2right ? i : queueSize - 1 - i;
            row[index] = node->val;
            
            if (node->left) nodeQueue.push(node->left);
            if (node->right) nodeQueue.push(node->right);
        }
        left2right = !left2right;
        res.push_back(row);
    }
    return res;
}
116. Populating Next Right Pointers in Each Node
Given a binary tree

    struct TreeLinkNode {
      TreeLinkNode *left;
      TreeLinkNode *right;
      TreeLinkNode *next;
    }
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Note:

You may only use constant extra space.
You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).
For example,
Given the following perfect binary tree,
         1
       /  \
      2    3
     / \  / \
    4  5  6  7
After calling your function, the tree should look like:
         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \  / \
    4->5->6->7 -> NULL
将二叉树使用next指针连接起来
void connect(TreeLinkNode *root) {
    if (!root) return;
    
    queue<TreeLinkNode*> nodeQueue;
    nodeQueue.push(root);
    while (!nodeQueue.empty()) {
        auto level = nodeQueue.size();
        for (auto i = 0; i < level; ++i) {
            TreeLinkNode* node = nodeQueue.front();
            nodeQueue.pop();
            
            if (i == level - 1) node->next = NULL;
            else node->next = nodeQueue.front();
            if (node->left) nodeQueue.push(node->left);
            if (node->right) nodeQueue.push(node->right);
        }
    }
}

相关文章

  • 5. 树

    树相关题目套路: 先序中序后序DFS其他遍历方式(如右左根)层序遍历 144. Binary Tree Preor...

  • 5. AVL树

    AVL树背景 在计算机科学中,AVL树是最先发明的自平衡二叉搜索树(BBST)。在AVL树中任何节点的两个子树的高...

  • 5. B+ 树

    插入 删除

  • 浙派园林的造园特色(九)

    5.植物配置 古人说:“山借树而为衣,树借山而为骨,树不可繁,要见山之秀丽;山不可乱,须显树之光辉”。明清苏...

  • 11.树Tree(1)

    目录:1.树的概念2.树的术语3.树的种类4.树的存储与表示5.树的常见的应用场景 1.树的概念 树的特点:1.每...

  • 5.二叉树

    [TOC] 写在前面 本篇文章整理《数据结构(C++语言版)》关于二叉树这种线性结构知识点。整个数据结构部分章节列...

  • 5.二叉搜索树

    Binary Search Tree 特征:任意一个节点的值,大于左子树所有节点的值,小于右子树所有节点的值。这个...

  • Element-ui中tree设置为单选及添加/修改/删除树

    1、首先创建树,配置下树的参数 2.data中设置一些值 3.设置方法: 4.添加树: 5.修改树: 6.删除树:

  • 6. 二叉树创建-查找

    1. 递归方式实现二叉树的构建2. 树、二叉树、二叉查找树3. 二叉树排序树的理解4. 二叉查找树5. 二叉树的查找

  • 树形结构

    数据结构中的元素存在一对多的相互关系 二叉树 2. 非二叉树 3. 自平衡二叉查找树 4. B树 5. Trie ...

网友评论

    本文标题:5. 树

    本文链接:https://www.haomeiwen.com/subject/kzenattx.html