[算法专题] Binary Tree

1 Same Tree

https://leetcode.com/problems/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.

分治的思想,如果root相等,再看左右子树是否相等。

/**
 * 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:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if (p == NULL && q == NULL) {
            return true;
        }

        if (p == NULL || q == NULL) {
            return false;
        }

        if (p->val != q->val) {
            return false;
        }

        return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
    }
};

2 SubTree

http://www.lintcode.com/en/problem/subtree/

You have two every large binary trees: T1, with millions of nodes, and T2, with hundreds of nodes. Create an algorithm to decide if T2 is a subtree of T1.

Example

T2 is a subtree of T1 in the following case:

       1                3
      / \              /
T1 = 2   3      T2 =  4
        /
       4

T2 isn‘t a subtree of T1 in the following case:

       1               3
      / \               T1 = 2   3       T2 =    4
        /
       4
仍然是分治的思想。如果T1当前root节点与T2的root节点相同,我们才有兴趣判断T2是否是T1的子树。如果不同,判断T2是否是T1的左子树的子树或者是T1的右子树的子树。
/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */
class Solution {
public:
    /**
     * @param T1, T2: The roots of binary tree.
     * @return: True if T2 is a subtree of T1, or false.
     */
    bool isSubtree(TreeNode *T1, TreeNode *T2) {
        if (T2 == NULL) {
            return true;
        }

        // //we have exhauste the root1 already
        if (T1 == NULL) {
            return false;
        }

        if (T1->val == T2->val) {
            if (isSameTree(T1, T2)) {
                return true;
            }
        }

        return isSubtree(T1->left, T2) || isSubtree(T1->right, T2);
    }

private:
    bool isSameTree(TreeNode *T1, TreeNode *T2) {
        if (T1 == NULL && T2 == NULL) {
            return true;
        }

        if (T1 == NULL || T2 == NULL) {
            return false;
        }

        if (T1->val != T2->val) {
            return false;
        }

        return isSameTree(T1->left, T2->left) && isSameTree(T1->right, T2->right);
    }
};

3 计算树的深度

int treeDepth(TreeNode *root) {
    // base case
    if (root == NULL) {
        return 0;
    } 

    return max(treeDepth(root->left), treeDepth(root->right)) + 1;
}

4 Path Sum

https://leetcode.com/problems/path-sum/

Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.

For example:

Given the below binary tree and sum = 22,

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

return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

/**
 * 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:
    bool hasPathSum(TreeNode* root, int sum) {
        // base case
        if (root == NULL) {
            return false;
        }

        // 当前递归层是否满足条件?
        if (root->val == sum && root->left == NULL && root->right == NULL) {
            return true;
        }

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

5 Path Sum II

https://leetcode.com/problems/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]
]
解法1:
dfs中的sum参数记录了当前递归层需要满足的条件
/**
 * 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:
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> result;
        vector<int> path;
        dfs(root, result, path, sum);
        return result;
    }

private:
    void dfs(TreeNode *root, vector<vector<int>> &result, vector<int> &path, int sum) {
        if (root == NULL) {
            return;
        }

        path.push_back(root->val);

        if (root->val == sum && root->left == NULL && root->right == NULL) {
            result.push_back(path);
        }

        dfs(root->left, result, path, sum - root->val);
        dfs(root->right, result, path, sum - root->val);

        path.pop_back();
    }
};

解法2:

考虑几个问题,dfs的对象是谁?什么时候满足push到result的条件?递归基是什么?

/**
 * 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:
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> result;
        vector<int> path;
        dfs(root, result, path, sum);
        return result;
    }

private:
    void dfs(TreeNode *root, vector<vector<int>> &result, vector<int> &path, const int &sum) {

        if (root == NULL) {
            return;
        }

        path.push_back(root->val);

        if (root->left == NULL && root->right == NULL) {

            int tmp = 0;

            for (vector<int>::const_iterator itr = path.cbegin(); itr != path.cend(); itr++) {
                tmp += *itr;
            }

            if (tmp == sum) {
                result.push_back(path);
            }
        }

        dfs(root->left, result, path, sum);
        dfs(root->right, result, path, sum);
        path.pop_back();
    }
};

6 Binary Tree Maximum Path Sum

https://leetcode.com/problems/binary-tree-maximum-path-sum/

Given a binary tree, find the maximum path sum.

The path may start and end at any node in the tree.

For example:

Given the below binary tree,

       1
      /      2   3

Return 6.

采用分治法。要求当前tree的最大路径和,可以考虑左子树的最大路径和、右子树的最大路径和、以及包含当前结点的最大路径和三者中的最大值。

要求包含当前结点的最大路径和,需要知道左子树的单路最大路径和leftChildSingleMaxSum、右子树的单路最大路径和rightChildSingleMaxSum。其中,max( leftChildSingleMaxSum + rightChildSingleMaxSum + root->val, leftChildSingleMaxSum + root->val, rightChildSingleMaxSum  + root->val),即为包含当前结点的最大路径和。

由以上分析,不难得知,遍历每一个节点时,需要得到其单路最大路径和以及双路最大路径和。我们将其封装为returnType。

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

    int singlePath_;
    int doublePath_;
};

class Solution {
public:
    int maxPathSum(TreeNode* root) {
        return maxPathSumHelper(root).doublePath_;
    }

private:
    returnType maxPathSumHelper(TreeNode *root) {
        if (root == NULL) {
            return returnType(0, numeric_limits<int>::min());
        }

        // devide
        returnType left = maxPathSumHelper(root->left);
        returnType right = maxPathSumHelper(root->right);

        // conquer
        int singlePath = getMax(left.singlePath_ + root->val, right.singlePath_ + root->val, root->val);
        int doublePath = getMax(left.doublePath_, right.doublePath_, max(left.singlePath_ + right.singlePath_ + root->val, singlePath));

        return returnType(singlePath, doublePath);
    }

    int getMax(int x, int y, int z) {
        return (x = x > y ? x : y ) > z ? x : z;
    }

};

7 最近公共祖先

http://www.lintcode.com/zh-cn/problem/lowest-common-ancestor/
 
最近公共祖先

给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。

最近公共祖先是两个节点的公共的祖先节点且具有最大深度。

样例

对于下面这棵二叉树

  4
 / 3   7
   /   5   6

LCA(3, 5) = 4

LCA(5, 6) = 7

LCA(6, 7) = 7

如果两个节点都在同一棵子树中,则继续往该子树中查找。如果两个节点在不同的子树中,那么root即为最近公共祖先。

/**
 * 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:
    TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {
        // p,q均在左子树中
        if (covers(root->left, p) && covers(root->left, q)) {
            return lowestCommonAncestor(root->left, q, p);
        }
        // p,q均在右子树中
        if (covers(root->right, p) && covers(root->right, q)) {
            return lowestCommonAncestor(root->right, q, p);
        }

        // base case:p,q在不同的子树中,或者root即为p,q中的某一个节点
        return root;
    }

    // 辅助函数,判断节点p是否在子树中。
    bool covers(TreeNode *root, TreeNode *p) {
        if (root == NULL) {
            return false;
        }

        if (root == p) {
            return true;
        }

        return covers(root->left, p) || covers(root->right, p);
    }
};

8 Convert Sorted Array to Binary Search Tree

Tree与其他数据结构转换这类题?目要求将树的结构转化成其他数据结构,例如linked list, array等,或者反之,从array等结构构成?棵树。

前者通常是通过树的遍历,合并局部解来得到全局解,而后者则可以利?分治的策略,递归将数据结构的两部分分别转换成子树,再合并。

https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/

Given an array where elements are sorted in ascending order, convert it to a height balanced BST.

/**
 * 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:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return sortedArrayToBstHelper(nums, 0, nums.size() - 1);
    }

private:
    TreeNode* sortedArrayToBstHelper(const vector<int> &nums, int start, int end) {

        if (start > end) {
            return NULL;
        }

        if (start == end) {
            return new TreeNode(nums[start]);
        }

        int mid = start + ((end - start) >> 1);
        TreeNode *l  = sortedArrayToBstHelper(nums, start, mid - 1);
        TreeNode *r = sortedArrayToBstHelper(nums, mid + 1, end);

        TreeNode *root = new TreeNode(nums[mid]);
        root->left = l;
        root->right = r;
        return root;
    }
};

9

 

时间: 2024-11-20 12:19:37

[算法专题] Binary Tree的相关文章

二叉树的各种遍历算法-leetcode Binary Tree Postorder Traversal 扩展

二叉树的各种遍历方法有  前序遍历   中序遍历    后序遍历  层序遍历.其中前三种遍历有递归程序可以实现,但是我们也有必要掌握其非递归版本的算法实现.正好在leetcode中遇到了遍历二叉树的问题,今天在这里一并总结了. 首先,引用leetcode中关于二叉树节点的定义. 1 // Definition for binary tree 2 struct TreeNode { 3 int val; 4 TreeNode *left; 5 TreeNode *right; 6 TreeNode

(算法)Binary Tree Max 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 does not need to go through the root. For ex

LeetCode算法题-Average of Levels in Binary Tree(Java实现)

这是悦乐书的第277次更新,第293篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第145题(顺位题号是637).给定一个非空二叉树,以数组的形式返回每一层节点值之和的平均值.例如: 3 / 9 20 / 15 7 输出:[3,14.5,11] 说明:第一层上的节点的平均值为3,第二层上的节点的平均值为14.5,第三层上的节点的平均值为11.因此返回[3,14.5,11]. 注意:节点值的范围在32位有符号整数的范围内. 本次解题使用的开发工具是eclipse,jd

Construct Binary Tree from Inorder and Postorder Traversal (算法课上的题)

Construct Binary Tree from Inorder and Postorder Traversal 这道题之前算法课上好像遇到过,思路也很简单的. 思路:后序序列的最后一个元素就是树根,然后在中序序列中找到这个元素(由于题目保证没有相同的元素,因此可以唯一找到),中序序列中这个元素的左边就是左子树的中序,右边就是右子树的中序,然后根据刚才中序序列中左右子树的元素个数可以在后序序列中找到左右子树的后序序列,然后递归的求解即可.(在去除了根节点之后,中序遍历和后序遍历的前N个树都是

笔试算法题(41):线索二叉树(Threaded Binary Tree)

出题:线索二叉树(Threaded Binary Tree) 分析: 为除第一个节点外的每个节点添加一个指向其前驱节点的指针,为除最后一个节点外的每个节点添加一个指向其后续节点的指针,通过这些额外的指针可以某种遍历方式对二叉树进行遍历,而加了这些额外指针的二叉树就是线索二叉树: 对于含有N个节点的二叉树而言,一共有2N个指针,但除了根节点的其他节点都有来自其父节点的指针,所以耗用了N-1个指针,则最终剩下2N-(N- 1)=N+1个空指针:线索二叉树就是利用这些空指针存储具有某种遍历顺序的前驱和

【LeetCode-面试算法经典-Java实现】【226-Invert Binary Tree(反转二叉树)】

[226-Invert Binary Tree(反转二叉树)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 代码下载[https://github.com/Wang-Jun-Chao] 原题 Invert a binary tree. 4 / 2 7 / \ / 1 3 6 9 to 4 / 7 2 / \ / 9 6 3 1 题目大意 将一棵二叉树进行翻转. 解题思路 对每一个结点,将它的左右子树进行交换,再对它的左右子结点进行同样的操作. 代码实现 树结点类 pub

【LeetCode-面试算法经典-Java实现】【105-Construct Binary Tree from Preorder and Inorder Traversal(构造二叉树)】

[105-Construct Binary Tree from Preorder and Inorder Traversal(通过前序和中序遍历构造二叉树)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given preorder and inorder traversal of a tree, construct the binary tree. Note: You may assume that duplicates do not exist in the

【LeetCode-面试算法经典-Java实现】【106-Construct Binary Tree from Inorder and Postorder Traversal(构造二叉树II)】

[106-Construct Binary Tree from Inorder and Postorder Traversal(通过中序和后序遍历构造二叉树)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given inorder and postorder traversal of a tree, construct the binary tree. Note: You may assume that duplicates do not exist in th

【LeetCode-面试算法经典-Java实现】【104-Maximum Depth of Binary Tree(二叉树的最大深度)】

[104-Maximum Depth of Binary Tree(二叉树的最大深度)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 题目大意 给定