二叉树 - 归档

LeetCode - 二叉树和递归

概述

名词性质

111. Minimum Depth of Binary Tree*

226. Invert Binary Tree**

100. Same Tree

101. Symmetric Tree***

222. Count Complete Tree Nodes***

110. Invert Binary Tree**

112. Path Sum**(递归返回条件)

404. Sum of Left Leaves**(递归返回条件)

257. Binary Tree Paths**(返回路径,回溯中全局变量引发的问题)

113. Path Sum II**(返回路径,回溯)

129. Sum Root to Leaf Numbers***(10^k + val, k为深度,回溯)

437. Path Sum III**(任意路径总和)

235. Lowest Common Ancestor of a Binary Search Tree**(递归实现遍历)

98. Validate Binary Search Tree**(区间传递)

450. Delete Node in a BST***(ALG4的代码是节点替换,这里是赋值替换代码更好理解)

108. Convert Sorted Array to Binary Search Tree*(二分法DFS)

230. Kth Smallest Element in a BST**(中序遍历求第k值)

236. Lowest Common Ancestor of a Binary Tree***(要注意p\q其中一个为root的情况,有点乱)




111. Minimum Depth of Binary Tree

在这里插入图片描述

  1. 递归解法
class Solution {
public:
    int minDepth(TreeNode* root) {
        if(root == NULL)
            return 0;
        if(root->left == NULL && root->right == NULL){
            return 1;
        }
        if(root->left == NULL)
            return minDepth(root->right) + 1;
        else if(root->right == NULL)
            return minDepth(root->left) + 1;
        else
            return min(minDepth(root->right), minDepth(root->left)) + 1;
    }
};
  1. BFS

  1. DFS

100. Same Tree

递归:

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(p == NULL && q == NULL)
            return true;
        if(p == NULL || q == NULL)
            return false;

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

迭代:


101. Symmetric Tree

在这里插入图片描述
还是容易让人一下想不出来的懵逼,四月份的时候还做过,完全想不起来了。

  1. 递归结构中,需要比较的是两棵树。
  2. helper比较的是两个子树是否对称。
  3. 与226的描述相对应,返回的是两颗子树是否对称(需要满足子树1的右孩子与子树2的左孩子,子树1的左孩子与子树2的右孩子相等),子树对称的话,再判断当前根节点下是否对称。
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(root == NULL || (root->left == NULL && root->right == NULL))
            return true;
            //helper比较的是两个子树是否对称.
        return helper(root->left, root->right);
        
    }
private:
    bool helper(TreeNode* left, TreeNode* right){
        if(left == NULL && right == NULL)
            return true;
        if(left == NULL || right == NULL)
            return false;
        //两颗子树,需要满足子树1的右孩子与子树2的左孩子,子树1的左孩子与子树2的右孩子相等
        return left->val == right->val && helper(left->right, right->left) && helper(left->left, right->right);

    }
};

222. Count Complete Tree Nodes

在这里插入图片描述

  1. 需要考虑到完全二叉树的性质,可以对最后一排节点数量使用二分法来确定。

递归穷举:

class Solution {
public:
    int countNodes(TreeNode* root) {
        if(root == NULL)
            return 0;
        nodes += 1;
        countNodes(root->left);
        countNodes(root->right);
        return nodes;
    }
private:
    int nodes = 0;
};

尽量简洁些,更能看出递归结构:

class Solution {
public:
    int countNodes(TreeNode* root) {
        if(root == NULL)
            return 0;
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};

二分思路:

class Solution {
public:
    int countNodes(TreeNode* root) {
        if(root == NULL)
            return 0;
        //getLeftDepth求出子树高度
        int lDepth = getLeftDepth(root->left);
        int rDepth = getLeftDepth(root->right);
        //左子树为满二叉树,右子树继续递归
        if(lDepth == rDepth){
            return pow(2, lDepth) + countNodes(root->right);
        }
        //左子树继续递归,右子树为满二叉树
        else{
            return pow(2, rDepth) + countNodes(root->left);
        }
    }
private:
    int getLeftDepth(TreeNode* root){
        int Depth = 0;
        while(root){
            Depth += 1;
            root = root->left;
        }
        return Depth;
    }
};

226. Invert Binary Tree

在这里插入图片描述
记得以前还做过这道题,现在看着还是很懵,看着答案也觉得有点不可思议,过于简洁有点看不出来反转二叉树过程具体是如何变化的。

  1. 递归结构中,需要对左右子树进行反转操作,反转后返回左右两个子树的根节点,然后对当前的根节点进行左右子树反转操作

后续遍历:

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == NULL){
            return NULL;
        }
        TreeNode* left = invertTree(root->left);
        TreeNode* right = invertTree(root->right);
        root->right = left;
        root->left = right;
        return root;
    }
};

前序遍历:


中序遍历:


112. Path Sum

在这里插入图片描述

  1. 要注意递归退出的条件(如何判断当前是叶子节点,而不是直接判断是否为NULL, 为NULL的时候,不一定是叶子节点下来的)
  2. 属于从底层返回结果的递归流程
class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if(root == NULL){
            return false;
        }
        //当前root为叶子节点,并且刚好能够把sum减完,就返回true;
        if(root->left == NULL && root->right == NULL && root->val == sum){
            return true;
        }
        if(hasPathSum(root->left, sum - root->val)){
            return true;
        }
        if(hasPathSum(root->right, sum - root->val)){
            return true;
        }
        return false;
    }
};

404. Sum of Left Leaves

在这里插入图片描述

  1. 当前节点上面才能判断出儿子节点是否为左叶子节点,当前节点无法判断当前节点是否为左叶子节点
  2. 左叶子节点的判断方法:
    root->left != NULL && root->left->left == NULL && root->left->right == NULL
    然后遍历整个二叉树将所有满足左叶子节点的数值加起来。
class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if(root == NULL){
            return 0;
        }
        return sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right) +
        (isLeftLeave(root) ? root->left->val : 0);
    }
private:
    bool isLeftLeave(TreeNode* root){
        if(root->left == NULL)
            return false;
        if(root->left->left == NULL && root->left->right == NULL){
            return true;
        }
        return false;
    }
};

257. Binary Tree Paths

在这里插入图片描述

递归:

class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> ret;
        string s;
        helper(root, ret, s);
        return ret;
    }
private:
    void helper(TreeNode* root, vector<string>& ret, string s){
        if(root == NULL)
            return;
        if(root->left == NULL && root->right == NULL){
            ret.push_back(s + to_string(root->val));
            return;
        }
        helper(root->left, ret, s + to_string(root->val) + "->");
        helper(root->right, ret, s + to_string(root->val) + "->");
    }
};

回溯法,回溯中全局变量string adds 导致回溯对象“2->”把顶层的回溯对象“1->”给覆盖了。,当需要回溯“1->”的时候,回溯到了“2->”,导致crash.
adds = to_string(root->val) + “->”;

class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> ret;
        string s;
        helper(root, ret, s);
        return ret;
    }
private:
    void helper(TreeNode* root, vector<string>& ret, string& s){
        if(root == NULL)
            return;
        if(root->left == NULL && root->right == NULL){
            s += to_string(root->val);
            ret.push_back(s);
            s.erase(s.rfind(to_string(root->val)), to_string(root->val).length());
            return;
        }
        adds = to_string(root->val) + "->";
        s += adds;
        helper(root->left, ret, s);
        helper(root->right, ret, s);
        s.erase(s.rfind(adds), adds.length());
        return;
    }
    string adds;
};

回溯法,效率并没有提升,只是写一下看看:

  class Solution {
  public:
      vector<string> binaryTreePaths(TreeNode* root) {
          vector<string> ret;
          string s;
          helper(root, ret, s);
          return ret;
      }
  private:
      void helper(TreeNode* root, vector<string>& ret, string& s) {
          if (root == NULL) {
              return;
          }
          if (root->left == NULL && root->right == NULL) {
              s += to_string(root->val);
              ret.push_back(s);
              s.erase(s.rfind(to_string(root->val)), to_string(root->val).length());
              return;
          }
          string adds = to_string(root->val) + "->";
          s += adds;
          helper(root->left, ret, s);
          helper(root->right, ret, s);
          s.erase(s.rfind(adds), adds.length());
          return;
      }
  };

113. Path Sum II

在这里插入图片描述
直接贴回溯了

class Solution {
public:
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> ret;
        if(root == NULL)
            return ret;
        vector<int> solution;
        helper(root, ret, solution, sum);
        return ret;
    }
    void helper(TreeNode* root, vector<vector<int>>& ret, vector<int>& solution, int sum){
        if(root == NULL)
            return;
        solution.push_back(root->val);
        if(root->left == NULL && root->right == NULL && root->val == sum){
            ret.push_back(solution);
            solution.pop_back();
            return;
        }
        helper(root->left, ret, solution, sum - root->val);
        helper(root->right, ret, solution, sum - root->val);
        solution.pop_back();
        return;
    }
};

129. Sum Root to Leaf Numbers

在这里插入图片描述

  1. 递归过程中每条路径的开始对每层的数值乘以10^k, k是节点的高度,相当于每次进入递归,都要把入参乘以10,然后加上当前节点的值, sum += 10*sum + root-val;
class Solution {
public:
    //1.如何从root节点开始对每层的数值乘以10^k,k是节点的高度
    //相当于每次进入递归,都要把入参乘以10,然后加上当前节点的值。
    //sum += 10*sum + root-val;
    int sumNumbers(TreeNode* root) {
        int ret = 0;
        int sum = 0;
        helper(root, sum, ret);
        return ret;
    }
private:
    void helper(TreeNode* root, int& sum, int& ret){
        if(root == NULL)
            return;
        sum = 10*sum + root->val;
        if(root->left == NULL && root->right == NULL){
            ret += sum;
        }
        helper(root->left, sum, ret);
        helper(root->right, sum, ret);
        sum = (sum - root->val) / 10;
        return;
    }
};

437. Path Sum III

路径可以任意不一定需要从root到leaf, 返回路径的数量
在这里插入图片描述

  1. 双重递归,外层递归只是为了遍历所有可以作为根节点的node,内层递归解决当前节点作为root节点的所有满足条件的路径的数量。
  2. root->val == sum的时候不能直接返回,因为路径中有负数,可能在更深层的递归中重新满足条件。
class Solution {
public:
    int pathSum(TreeNode* root, int sum) {
        int res = 0;
        if(root == NULL){
            return 0;
        }
        res = helper(root, sum);
        res += pathSum(root->left, sum);
        res += pathSum(root->right, sum);
        return res;
    }
private:
    int helper(TreeNode* root, int sum){
        int ret = 0;
        if(root == NULL){
            return 0;
        }
        if(root->val == sum){
            ret += 1;
            //不要在这里返回,路径中有负数。
        }
        ret += helper(root->left, sum - root->val);
        ret += helper(root->right, sum - root->val);
        return ret;
    }
};

前缀和解法?


235. Lowest Common Ancestor of a Binary Search Tree

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == NULL){
            return NULL;
        }
        if(root->val > p->val && root->val > q->val){
            return lowestCommonAncestor(root->left, p, q);
        }
        else if(root->val < p->val && root->val < q->val){
            return lowestCommonAncestor(root->right, p, q);
        }
        else{
            return root;
        }
    }
};

98. Validate Binary Search Tree

在这里插入图片描述

class Solution {
public:
    bool isValidBST(TreeNode* root) {

        return helper(root, LONG_MIN, LONG_MAX);
    }
private:
    bool helper(TreeNode* root, long min, long max){
        if(root == NULL){
            return true;
        }
        if(root->val > min && root->val < max){
            return helper(root->left, min, root->val) && helper(root->right, root->val, max);
        }
        return false;
    }
};

450. Delete Node in a BST

在这里插入图片描述

  1. del node 如果没有双子节点,那么直接返回其中一个节点
  2. del node 如果有两个双子节点,将del node赋值为它的后继节点的值,然后删掉它的后继节点 root->right = deleteMin(root->right).
class Solution {
public:
    //递归deleteNode找到key,找到它的后继节点,key赋值为后继节点,删除后继节点。
    TreeNode* deleteNode(TreeNode* root, int key) {
        if(!root) return NULL;
        if(root->val < key)
            root->right = deleteNode(root->right, key);
        else if(root->val > key)
            root->left = deleteNode(root->left, key);
        //找到keyNode.
        else{
            if(root->left == NULL)
                return root->right;
            if(root->right == NULL)
                return root->left;
            //删除keyroot的后继节点
            root->right = deleteMin(root->right);
            //将key赋值为后继节点的值
            root->val = tail;
        }
        return root;
    }
private:
    //删除查找树的最小节点,返回删除节点的右节点
    TreeNode* deleteMin(TreeNode* root){
        if(root == NULL)
            return NULL;
        if(root->left == NULL){
            tail = root->val;
            return root->right;
        }
        root->left = deleteMin(root->left);
        return root;
    }
    int tail = 0;
};

108. Convert Sorted Array to Binary Search Tree

在这里插入图片描述

  1. DFS二分法:
class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return helper(nums, 0, nums.size() - 1);
    }
private:
    TreeNode* helper(vector<int>& nums, int left, int right){
        if(left > right)
            return NULL;
        int mid = (left + right) / 2;
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = helper(nums, left, mid - 1);
        root->right = helper(nums, mid + 1, right);
        return root;

    }
};
  1. BFS

230. Kth Smallest Element in a BST

在这里插入图片描述

  1. 中序BST
class Solution {
public:
    //栈模拟中序遍历,遇到第k个数的时候可以返回,不用遍历完整个搜索树
    int kthSmallest(TreeNode* root, int k) {
        stack<TreeNode*> st;
        int n = 0;
        while(true){
            while(root){
                st.push(root);
                root = root->left;
            }
            //最左节点出栈访问,记录出栈访问次数n
            TreeNode* node = st.top();
            st.pop();
            if(++n == k)
                return node->val;
            //最左节点的右节点入栈
            root = node->right;

        }
    }
};
  1. 栈模拟中序迭代
class Solution {
public:
    //栈模拟中序遍历,遇到第k个数的时候可以返回,不用遍历完整个搜索树
    int kthSmallest(TreeNode* root, int k) {
        stack<TreeNode*> st;
        int n = 0;
        while(true){
            while(root){
                st.push(root);
                root = root->left;
            }
            //最左节点出栈访问,记录出栈访问次数n
            TreeNode* node = st.top();
            st.pop();
            if(++n == k)
                return node->val;
            //最左节点的右节点入栈
            root = node->right;
        }
    }
};

236. Lowest Common Ancestor of a Binary Tree

在这里插入图片描述

  1. 235类似但是不是BST.
  2. 递归形式越简单,越不容易理解,尤其是在left、right不全为NULL的递归逻辑中。。。
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == NULL || root->val == p->val || root->val == q->val)
            return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if(left && right)
            return root;
        else
            return left ? left : right;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值