美文网首页刷题总结
二叉树 LeetCode 刷题小结(二)

二叉树 LeetCode 刷题小结(二)

作者: 思想永不平凡 | 来源:发表于2020-02-11 13:56 被阅读0次

在上节的基础上,本节我们将继续汇总一些 LeetCode 有关二叉树的题。



我们还是使用上节的程序框架,可以手动输入样例并测试,解题的方法不唯一。
所有题均来自于leetcode

翻转二叉树

翻转一棵二叉树。

图片.png

这个题需要我们翻转二叉树,可以用递归来实现。
当一个节点为空,需不需要交换都无所谓;当其不为空时,交换该节点的左右子树即可,继续递归其左右子树,只要遍历到每一个节点就可以了,遍历到该节点,就换交换其左右子树,以什么方式遍历的其实无所谓。
简单来说就是,每一个节点做好自己的事情:交换该节点的左右子树。每个节点做好这件事,再顾及到每个节点,二叉树就翻转成功了。

具体的程序如下:

//226 翻转二叉树
BiTree invertTree(BiTree root){
    if(root == NULL){
        return NULL;
    }
    BiTree r = invertTree(root->right);
    BiTree l = invertTree(root->left);

    root->left = r;
    root->right = l;
    return root;
}

测试程序:

int main(){
    // test
    //cout<<"test:......"<<endl;
    BiTree tree = levelCreate();
    tree = invertTree(tree);
    levelOrder(tree);
    return 0;
}

测试结果为:

4
2 7
1 3 6 9
# # # # # # # #
4 7 2 9 6 3 1

左叶子之和

计算给定二叉树的所有左叶子之和。

图片.png

这个题首先要明确什么是左叶子,节点为空,不操作,若一个节点是左叶子,取它的值相加,之和明确什么时候递归左子树,右子树,这个问题就不难了。

具体程序:

// 404 左叶子之和
void sumOfLeftLeaves_helper(BiTree root,int& sum){
    if(root == NULL){
        sum = sum;
    }else{
        if(root->left != NULL){
            // 左叶子的条件
            if(root->left->left == NULL && root->left->right == NULL){
                sum += stoi(root->left->val);
            }else{
                sumOfLeftLeaves_helper(root->left,sum);
            }
            if(root->right != NULL){
                sumOfLeftLeaves_helper(root->right,sum);
            }
        }
    }
}
int sumOfLeftLeaves(BiTree root){
    int sum = 0;
    sumOfLeftLeaves_helper(root,sum);
    return sum;
}

测试程序:

int main(){
    // test
    //cout<<"test:......"<<endl;
    BiTree tree = levelCreate();
    cout<<sumOfLeftLeaves(tree)<<endl;
    return 0;
}

测试结果:

3 
9 20
# # 15 7
# # # #
24

二叉树的中序遍历

给定一个二叉树,返回它的中序遍历。

图片.png

这个,我在之前的博客《二叉树常见操作的 C++ 实现(一)》,介绍过递归与非递归的前,中,后序遍历以及层次遍历。
这里,我们再回顾一下吧。

递归版

递归版的很简单。
具体程序如下:

// 94 二叉树的中序遍历,递归版
void inorderTraversal_helper(BiTree root,vector<int>& res){
    if(root == NULL){
        return ;
    }
    inorderTraversal_helper(root->left,res);
    res.push_back(stoi(root->val));
    inorderTraversal_helper(root->right,res);
}
vector<int> inorderTraversal(BiTree root){
    vector<int> res;
    inorderTraversal_helper(root,res);
    return res;
}

测试程序如下:

int main(){
    // test
    //cout<<"test:......"<<endl;
    BiTree tree = levelCreate();
    vector<int> res = inorderTraversal(tree);
    for(auto r : res){
        cout<<r<<" ";
    }
    cout<<endl;
    return 0;
}

测试结果:

1
# 2
3 #
# #
1 3 2

非递归版

具体程序如下:

// 94 二叉树的中序遍历,非递归版
vector<int> inorderTraversal_(BiTree root){
    stack<BiTree> m;
    vector<int> res;
    BiTree rt = root;
    while(rt != NULL|| m.size() != 0){
        while(rt != NULL){
            m.push(rt);
            rt = rt->left;
        }
        rt = m.top();
        m.pop();
        res.push_back(stoi(rt->val));
        rt = rt->right;
    }
    return res;
}

测试程序:

int main(){
    // test
    //cout<<"test:......"<<endl;
    BiTree tree = levelCreate();
    vector<int> res = inorderTraversal_(tree);
    for(auto r : res){
        cout<<r<<" ";
    }
    cout<<endl;
    return 0;
} 

测试结果:

1
# 2
3 #
# #
1 3 2

验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

图片.png

这个题可以使用递归,也可以使用非递归方法。

递归

具体程序如下:

// 98 验证二叉搜索树,递归
bool isValidBST_helper(BiTree root,long l,long r){
    if(root == NULL){
        return true;
    }
    if(l >= stoi(root->val) || r <= stoi(root->val)){
        return false;
    }
    if(isValidBST_helper(root->left,l,stoi(root->val)) && isValidBST_helper(root->right,stoi(root->val),r)){
        return true;
    }
    return false;
}
bool isValidBST(BiTree root){
    return isValidBST_helper(root,LONG_MIN,LONG_MAX);
}

测试程序:

int main(){
    // test
    //cout<<"test:......"<<endl;
    BiTree tree = levelCreate();
    cout<<isValidBST(tree)<<endl;
    return 0;
}

测试结果:

2
1 3
# # # #
1
5
1 4
# # 3 6
# # # #
0

非递归

具体程序如下:

// 98 验证二叉搜索树,非递归
bool isValidBST_(BiTree root){
    stack<BiTree> sk;
    long temp = LONG_MIN;
    while(root || sk.size()){
        while(root){
            sk.push(root);
            root = root->left;
        }
        root = sk.top();
        sk.pop();
        if(temp >= stoi(root->val)){
            return false;
        }
        temp = stoi(root->val);
        root = root->right;
    }
    return true;
}

测试程序:

int main(){
    // test
    //cout<<"test:......"<<endl;
    BiTree tree = levelCreate();
    cout<<isValidBST_(tree)<<endl;
    return 0;
}

测试结果为:

2
1 3
# # # #
1
5
1 4
# # 3 6
# # # #
0

二叉树的层次遍历

给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

图片.png

二叉树的层次遍历在之前的博客中也是提到过的,这里我们再回顾一遍吧。
关键点是用队列保存每一层节点,在本层节点数据域被保存后,用队列保存下一层节点,直到遍历完每一层。

具体的程序如下:

// 102 二叉树的层次遍历,由于本题的代码模板函数和原有的函数重复了,在原函数的基础上增加了下划线以区分
vector<vector<int>> levelOrder_(BiTree root){
    vector<vector<int>> res;
    queue<BiTree> q;
    if(root == NULL){
        return res;
    }
    q.push(root);
    while(!q.empty()){
        //, ,每一层的节点数
        int n = q.size();
        //用以存储该层节点的数据域
        vector<int> level;
        while(n--){
            //以此将本层的节点出队列
            BiTree node = q.front();
            q.pop();
            //存入level中
            level.push_back(stoi(node->val));
            if(node->left){
                q.push(node->left);
            }
            if(node->right){
                q.push(node->right);
            }
        }
        //保存该层所有节点
        res.push_back(level);
    }
    return res;
}

测试程序:

int main(){
    // test
    //cout<<"test:......"<<endl;
    BiTree tree = levelCreate();
    vector<vector<int>> res = levelOrder_(tree);
    for(auto r : res){
        for(auto _r : r){
            cout<<_r<<" ";
        }
        cout<<endl;
    }
    return 0;
}

测试结果为:

3
9 20
# # 15 7
# # # #
3
9 20
15 7

二叉树的锯齿形层次遍历

给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

图片.png

这个题和上一题很相似,但是有所不同,若根节点算第一层的话,奇数层是从左到右记录的,偶数层是从右到左记录的。
那么我们使用一个栈是不够的,需要有两个栈,一个从左到右记录,一个从右到左记录,先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行。直到两个栈都为空了,遍历完成。

具体程序如下:

// 103 二叉树的锯齿形层次遍历
vector<vector<int>> zigzagLevelOrder(BiTree root){
    vector<vector<int>> res;
    if(root == NULL){
        return res;
    }
    //设置两个栈,一个从左到右记录,一个从右到左记录
    //即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行
    stack<BiTree> left_stack,right_stack;
    //奇数层,从左到右记录,记录完后将该层所有节点的左,右子节点压入右栈
    //偶数层,从右到左记录,记录完后将该层所有节点的右,左子节点压入左栈
    left_stack.push(root);
    while(left_stack.size() != 0 || right_stack.size() != 0){
        if(left_stack.size() != 0){
            res.push_back(vector<int> ());
            while(left_stack.size() != 0){
                //得到当前节点
                BiTree node = left_stack.top();
                left_stack.pop();
                res.back().push_back(stoi(node->val));
                //左节点压入右栈
                if(node->left){
                    right_stack.push(node->left);
                }
                //右节点压入右栈
                if(node->right){
                    right_stack.push(node->right);
                }
            }
        }
        if(right_stack.size() != 0){
            res.push_back(vector<int> ());
            while(right_stack.size() != 0){
                //得到当前节点
                BiTree node = right_stack.top();
                right_stack.pop();
                res.back().push_back(stoi(node->val));
                //右节点压入左栈
                if(node->right){
                    left_stack.push(node->right);
                }
                //左节点压入左栈
                if(node->right){
                    left_stack.push(node->left);
                }
            }
        }
    }
    return res;
}

测试程序如下:

int main(){
    // test
    //cout<<"test:......"<<endl;
    BiTree tree = levelCreate();
    vector<vector<int>> res = zigzagLevelOrder(tree);
    for(auto r : res){
        for(auto _r : r){
            cout<<_r<<" ";
        }
        cout<<endl;
    }
    return 0;
}

测试结果如下:

3
9 20
# # 15 7
# # # #
3
20 9
15 7

全部代码见 github ,main.cpp 中不带测试程序。
本节内容到此结束,之后将继续更新。

相关文章

  • 二叉树 LeetCode 刷题小结(二)

    在上节的基础上,本节我们将继续汇总一些 LeetCode 有关二叉树的题。 我们还是使用上节的程序框架,可以手动输...

  • leetcode刷题之深度搜索

    leetcode刷题,使用python 1,二叉树的中序遍历 —— 0094 中序遍历给定一个二叉树的根节点 r...

  • 二叉树 LeetCode 刷题小结(一)

    本节我们将汇总一些 LeetCode 有关二叉树的题。 鉴于 LeetCode 测试的方式是系统给出样例并自动测试...

  • 二叉树 LeetCode 刷题小结(六)

    在上节的基础上,本节我们将继续汇总一些 LeetCode 有关二叉树的题。 接着上节,我们继续汇总二叉树相关的例题...

  • 二叉树 LeetCode 刷题小结(五)

    在上节的基础上,本节我们将继续汇总一些 LeetCode 有关二叉树的题。 接着上节,我们还是使用之前的程序框架,...

  • 二叉树 LeetCode 刷题小结(三)

    在上节的基础上,本节我们将继续汇总一些 LeetCode 有关二叉树的题。 接着上节,我们还是使用之前的程序框架,...

  • 二叉树 LeetCode 刷题小结(四)

    在上节的基础上,本节我们将继续汇总一些 LeetCode 有关二叉树的题。 接着上节,我们还是使用之前的程序框架,...

  • 二叉树 LeetCode 刷题小结(七)

    在上节的基础上,本节我们将继续汇总一些 LeetCode 有关二叉树的题。 接着上节,我们继续汇总二叉树相关的例题...

  • LeetCode 刷题小结杂谈(二)

    这节我们继续来汇总一些LeetCode题 找到所有数组中消失的数字 给定一个范围在 1 ≤ a[i] ≤ n (...

  • 【算法题】递归求二叉树深度

    二叉树的深度算法,是二叉树中比较基础的算法了。对应 LeetCode 第104题。 然后你会发现 LeetCode...

网友评论

    本文标题:二叉树 LeetCode 刷题小结(二)

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