关于Leetcode上二叉树的算法总结

  二叉树,结构很简单,只是比单链表复杂了那么一丢丢而已。我们先来看看它们结点上的差异:

/* 单链表的结构 */
struct SingleList{
    int element;
    struct SingleList *next;
};
/* 二叉树的结构 */
struct BinaryTree{
    int element;
    struct BinaryTree *left;
    struct BinaryTree *right;
};

  根据以上两个结构,我们不难发现,单链表的结点只有一个指向下一结点的指针,而二叉树中有两个。也就是说单链表每个结点只有一个子节点,而二叉树有两个子节点(其中一个可能为NULL)。了解了这一点的区别,我们就知道:基于二叉树的算法比基于单链表的算法差异就是每次遍历一个结点之后,需要遍历两个子节点,而单链表只需要遍历一个子节点。

  这就引出了2种遍历的方法:广度优先遍历(BFS)深度优先遍历(DFS)。

  对于单链表来说,BFS和DFS是一样的,因为每个节点只有一个子节点,每次遍历下一个节点只有一种选择;但是二叉树每个节点有两个子节点,也就是说遍历的顺序既可以遍历它的子节点(无论左节点还是右结点都是DFS),也可以遍历它的兄弟结点。如果是每次先遍历子节点那么就是DFS;每次先遍历兄弟结点,就是BFS。

  DFS采用栈结构,博主这里用的是递归来实现栈,当然大家也可以用stack来实现;BFS采用的是队列queue。

void dfs(BinaryTree *root){
    if(NULL == root)
        return ;
    dfs(root->left);
    dfs(root->right);
}
void bfs(BinaryTree *root){
    if(NULL == root)
        return ;
    queue<BinaryTree *> que;
    que.push();
    while(!que.empty()){
        BinaryTree *pNode = que.front();
      que.pop();        if(pNode->left)
            que.push(pNode->left);
        if(pNode->right)
            que.push(pNode->right);
    }
}

  关于树的一些算法中,DFS和BFS一般都适用,但是当涉及到根到叶的路径这类问题时,最好还是用DFS来实现。如下所示:

1、给一棵二叉树和一个值Sum,求出所有从根到叶子的值等于Sum的所有路径。

  思路:深度优先搜索(DFS),然后把从跟开始每次访问一个结点就把该结点添加到一个vec的最后位置,并把sum减去当前借点的值后传递给下一个节点,当一个结点的左右孩子都为NULL,并且值等于sum时,就说明该节点是叶子节点,并且从根结点到该节点的路径和为Sum,把vec,添加到res中;每次返回时,需要把vec中的最后一个值删除,因为每个节点有两个子节点,从根节点到左孩子的叶子的路径与到右孩子叶子的路径是不同的,所有每次访问完左孩子或者右孩子需要把孩子的值从vec中删除。

/**
 * 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 {
private:
    vector<vector<int>> res;
    vector<int> vec;
    void _pathSum(TreeNode* root, int sum){
        if(root == NULL)
            return ;
        vec.push_back(root->val);
        if(root->left == NULL && root->right == NULL && sum == root->val){
            res.push_back(vec);
            return ;
        }
        _pathSum(root->left, sum-root->val);
        if(root->left)
            vec.pop_back();
        _pathSum(root->right, sum-root->val);
        if(root->right)
            vec.pop_back();
    }
public:
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        if(NULL == root)
            return res;
        _pathSum(root, sum);
        return res;
    }
};

2、转化二叉树

把二叉树:

    4
   /     2     7
 / \   / 1   3 6   9

转化成

     4
   /     7     2
 / \   / 9   6 3   1

  思路:这个既可以用DFS也可以用BFS,也就是遍历每个节点,然后将它们的左右孩子互换即可。这里采用BFS来实现:

/**
 * 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* invertTree(TreeNode* root) {
        if(NULL == root)
            return NULL;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()){
            TreeNode* pChild = que.front();
            que.pop();
            TreeNode* pNode = pChild->left;
            pChild->left = pChild->right;
            pChild->right = pNode;
            if(pChild->left)
                que.push(pChild->left);
            if(pChild->right)
                que.push(pChild->right);
        }
        return root;
    }
};

 3、总结

  只要掌握了DFS和BFS的思想,其它关于二叉树的算法基本上都是类似的,必要的时候通过画图来让自己感性认识一下也是极好的。

  关于Leetcode上的题目代码:https://github.com/whc2uestc/onlineJudge/tree/master/leetCode

版权所有,欢迎转载,转载请注明出处。

时间: 2024-10-08 16:33:19

关于Leetcode上二叉树的算法总结的相关文章

Python中的二叉树查找算法模块

问题 思路说明 二叉树查找算法,在开发实践中,会经常用到.按照惯例,对于这么一个常用的东西,Python一定会提供轮子的.是的,python就是这样,一定会让开发者省心,降低开发者的工作压力. python中的二叉树模块内容: BinaryTree:非平衡二叉树 AVLTree:平衡的AVL树 RBTree:平衡的红黑树 以上是用python写的,相面的模块是用c写的,并且可以做为Cython的包. FastBinaryTree FastAVLTree FastRBTree 特别需要说明的是:树

同一个程序eclipse上运行的结果与leetcode上运行的不一样

题目为leetcode第一道题Two Sum,以下为java写的代码: 当输入数据target=0,  nums=[0,4,3,0]时,eclipse上运行的结果与leetcode上运行的不同 1.eclipse下的运行结果: 2.leetcode下的运行结果: 把算法仔细理了一遍觉得并没有错 ,写的第一个leetcode卡在这了,好纠结!会不会是两者编译器差异造成的?以下贴出完整代码:

动态规划第五讲——leetcode上的题目动态规划汇总(上)

本节,我们将对leetcode上有关DP问题的题目做一个汇总和分析. 1.题目来源 Interleaving String 动态规划 二叉树 Unique Binary Search Trees 动态规划 二叉树 Word Break 动态规划 N/A Word Break II 动态规划 N/A Palindrome Partitioning 动态规划 N/A Palindrome Partitioning II 动态规划 N/A Triangle 动态规划 N/A Distinct Subs

[LeetCode系列] 二叉树最大深度求解问题(C++递归解法)

问: 给定二叉树, 如何计算二叉树最大深度? 算法描述如下: 如果当前节点为空, 返回0(代表此节点下方最大节点数为0) 如果当前节点不为空, 返回(其左子树和右子树下方最大节点数中的最大值+1) 上述算法的精髓在于递归调用中的终止条件. 代码如下: 1 /** 2 * Definition for binary tree 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNod

Leetcode 297.二叉树的序列化和反序列化

二叉树地序列化和反序列化 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据. 请设计一个算法来实现二叉树的序列化与反序列化.这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构. 示例:  你可以将以下二叉树: 序列化为 "[1,2,3,null,null,4,5]" 提示: 这与 Le

关于leetcode上两数之和的思考

今天在leetcode上完成这道题目时: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元素. 示例: 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9所以返回 [0, 1] 初步代码为 1 class Solution { 2 public int[] t

leetcode 137 && 360一面算法

题目描述:给一个数组,有一个数出现了两次或者1次,而其他数都出现了三次,找出这个数.其实对应了leetcode 137. 网上的解法多是位运算 public int singleNumber(int[] nums) {     int ans = 0;     for(int i = 0; i < 32; i++) {         int sum = 0;           for(int j = 0; j < nums.length; j++) {              if(((

morris算法-----高级二叉树遍历算法

在遍历儿叉树时,常常使用的是递归遍历,或者是借助于栈来迭代,在遍历过程中,每个节点仅访问一次,所以这样遍历的时间复杂度为O(n),空间复杂度为O(n),并且递归的算法易于理解和实现.在遍历过程中,递归遍历过程的空间复杂度却是O(n),就算是转换为使用栈空间迭代时间,还是没有改变算法对额外空间的需求,在学习数据结构课程时,还学习了线索二叉树,在线索二叉树中,使用线索来保存节点的前驱和后继的信息,而这些线索是利用了叶节点的空指针域来保存,所以知道了树种每个节点的前驱和后继的位置(指针)可以有效降低遍

[leetcode]重建二叉树(先序和终须) 中序遍和后续

分割后长度相等,就是参数麻烦,p,先序的起始点, ib,ie 终须的结束和开始. 1 /** 2 * Definition for binary tree 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 public class Solution { 11 public TreeNode bu