【算法——二叉树】

目录

1.简单

2.中等

2.1验证二叉搜索树

2.2二叉树的中序遍历

2.3二叉树的层次遍历

2.4二叉树的锯齿形层次遍历

3.困难

3.1恢复二叉搜索树

1.简单

2.中等

2.1验证二叉搜索树

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

假设一个二叉搜索树具有如下特征:

节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

输入:
    2
   / \
  1   3
输出: true
示例 2:

输入:
    5
   / \
  1   4
     / \
    3   6
输出: false

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/validate-binary-search-tree
 

学过验证二叉搜索树的方法:中序遍历,所得到的节点数值肯定是递增的。所以设置一个last指针指向中序遍历过程中当前节点的上一个节点。

TreeNode* last = nullptr;
bool flag = false; //如果出现last->val >= t->val的情况,置true

void ldr(TreeNode *t){
    if(t){
        ldr(t->left);
        if(last == nullptr){  //最左的一个节点
            last = t;
        }
        if(last != t){
            if(last->val >= t->val)
                flag = true;
        }
        last = t;
        ldr(t->right);
    }
}

bool isValidBST(TreeNode* root) {

    ldr(root);

    return !flag;
}

2.2二叉树的中序遍历

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

示例:

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

输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal
 

中序遍历的递归方法很简单了

void ldr(vector<int> &res, TreeNode* p){
    if(p){
        ldr(res, p->left);
        res.push_back(p->val);
        ldr(res, p->right);
    }
}

迭代算法很容易想到用栈,但是结束条件是什么呢?因为栈在迭代过程中会出现为空的情况。 根据观察可以发现,当迭代到最右端的节点(如果它有左节点,应该是已经遍历到了),它的右节点为空,此时栈也为空,所以为结束条件。

void fun(vector<int> &res, TreeNode* t){
    stack<TreeNode*> stack1;
    while (t != nullptr || !stack1.empty()){
        while(t){  //先依次把左节点加入到栈
            stack1.push(t);
            t = t->left;
        }
        t = stack1.top();  //提出栈顶元素
        res.push_back(t->val);
        stack1.pop();
        t = t->right; //t可能为空或指向右节点
    }
}

vector<int> inorderTraversal(TreeNode* root) {
    vector<int> res;
    fun(res, root);
    return res;
}

2.3二叉树的层次遍历

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

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal
 

int count = 0; // 每层节点计数
int flag = 1; // 记录下一层结束的位置

vector<vector<int>> levelOrder(TreeNode* root) {
    vector<vector<int>> res;
    if(root == nullptr)
        return res;
    queue<TreeNode*> que;
    vector<int> temp;
    que.push(root);
    while (!que.empty()){
        TreeNode* t = que.front();
        temp.push_back(t->val);
        count++;
        if(t->left) que.push(t->left);
        if(t->right) que.push(t->right);
        que.pop();
        //一层结束
        if(count == flag){
            res.push_back(temp);
            temp.clear();
            flag = que.size();
            count = 0;
        }
    }
    return res;
}

2.4二叉树的锯齿形层次遍历

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

    3
   / \
  9  20
    /  \
   15   7
返回锯齿形层次遍历如下:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal
使用双向队列(C++中为deque),每层分为前取后放(一般的队列)和前放后取两种情况,交替进行。

int count = 0;
int flag = 1;
int zigzagFlag = 0;

vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
    vector<vector<int>> res;
    if(root == nullptr)
        return res;
    deque<TreeNode*> que;
    vector<int> temp;
    que.push_back(root);
    while (!que.empty()){
        if(zigzagFlag == 0){  //前取后放
            TreeNode* t = que.front();
            temp.push_back(t->val);
            que.pop_front();
            if(t->left) que.push_back(t->left);
            if(t->right) que.push_back(t->right);
        } else{ //后取前放
            TreeNode* t = que.back();
            temp.push_back(t->val);
            que.pop_back();
            if(t->right) que.push_front(t->right);
            if(t->left) que.push_front(t->left);
        }
        count++;
        //一层
        if(count == flag){
            res.push_back(temp);
            temp.clear();
            flag = que.size();
            count = 0;

            if(zigzagFlag == 0)
                zigzagFlag = 1;
            else
                zigzagFlag = 0;
        }
    }
    return res;
}

2.5不同的二叉搜索树

给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?

示例:

输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-binary-search-trees
不看参考是真的想不出来,卡特兰数,tql。

https://leetcode-cn.com/problems/unique-binary-search-trees/solution/hua-jie-suan-fa-96-bu-tong-de-er-cha-sou-suo-shu-b/

int numTrees(int n) {
    vector<int> dp(n + 1);
    dp[0] = 1;
    dp[1] = 1;

    for (int i = 2; i < n + 1; ++i) {
        for (int j = 1; j < i + 1; ++j) {
            dp[i] += dp[j - 1] * dp[i - j];
        }
    }

    return dp[n];
}

3.困难

3.1恢复二叉搜索树

二叉搜索树中的两个节点被错误地交换。

请在不改变其结构的情况下,恢复这棵树。

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

   1
  /
 3
  \
   2

输出: [3,1,null,null,2]

   3
  /
 1
  \
   2

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/recover-binary-search-tree
这道题我的做法跟验证二叉搜索树一样,递归的中序遍历,如例子中,遍历的顺序是【3,2,1】,3>2显然不是二叉搜索树,但具体是跟哪个节点交换,还要记录当前值,继续递归,直到遍历到1节点,即检测到非二叉搜索树后中序遍历,最小的那个节点。将3和1交换。

TreeNode *last = nullptr, *x = nullptr, *y = nullptr;
int flag = 0;

void ldr(TreeNode* t){
    if(t){
        ldr(t->left);
        if(last == nullptr){
            last = t;
        } else{
            if(flag == 0){
                if(last->val > t->val){
                    flag = 1;
                    x = last; //记录非二叉搜索开始节点
                    y = t;
                }
            } else{
                if(t->val < y->val){
                    y = t; //寻找最小的节点
                }
            }
        }
        last = t;
        ldr(t->right);
    }
}

void recoverTree(TreeNode* root) {
    ldr(root);
    swap(x->val, y->val);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值