二叉树与经典问题

树的结构定义

链表定义:

typedef struct Node{
	int data;
	struct Node *next;
}Node,*LinkList;
(链表是一种特殊的树形结构)

将单一指针域的链表转变多指针域的树:

typedef struct Node{
	int data;
	struct Node *next[3];
}Node,*Tree;

二叉树注:

  1. 每个节点最多有2度
  2. 度为0的节点比度为2的节点多1个 => n个结点的树边有n-1条
    证明2:n0+n1+n2 (左边为节点数) = 0n0+1n1+2*n2+1(右边为边数+1) =>n0=n2+1

二叉树的遍历
前序遍历 根 左 右
中序遍历 左 根 右
后序遍历 左 右 根

二叉树的种类

完全二叉树(complete binary tree)
定义:只在最后一层右边缺少1个结点
性质:
  1. 编号为i的子节点:
    左孩子编号:2 * i
    右孩子编号:2 * i + 1

  2. 可以用连续空间存储(数组)

  3. 子树的地址可以通过父节点计算得到
    (好处:不需要记录左右子树的地址 可以节省大量存储空间)(记录式与计算式存储方式的区别)

满二叉树(full binary tree)
完美二叉树(perfect binary tree)

二叉树做题思路

二叉树用途

关于树结构的深入理解:

结点:集合
边:关系
主要用与查找操作

练习递归技巧的最佳选择

  1. 数学递归法 - 》 结构递归法
  2. 赋予递归函数一个明确的意义
  3. 思考边界条件
  4. 实现递归过程

二叉树的前序遍历:(Leetcode-144)

1.函数意义:前序遍历以root为根结点的二叉树
2.边界条件:root为空时不需要遍历
3.递归过程:前序遍历左子树,前序遍历右子树

N叉树的前序遍历:(Leetcode-589)

1.函数意义:前序遍历以root为根结点的N叉树
2.边界条件:root为空时不需要遍历
3递归过程:前序遍历root下的每一棵子树

完全二叉树左孩子右兄弟表示法节省空间
C++前置基础:C语言,操作系统,底层原理,网络编程,数据结构上、下,面试算法上、下=》C++

练习题:

  • leetcode-110(平衡二叉树)
class Solution {
public:
    int getHeight(TreeNode *root){
        if(root == NULL)return 0;
        int l = getHeight(root->left);
        int r = getHeight(root->right);
        if(l<0 || r<0) return -2;
        if(abs(l-r)>1)return -2;
        return max(l,r) + 1; 
    }
    bool isBalanced(TreeNode* root) {
        return getHeight(root)>=0;
    }
};
  • leetcode-112(路径总和)
class Solution {
public:

    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == NULL) return false;
        if(root->left == NULL && root->right == NULL) return root->val = targetSum;
        if(root->left && hasPathSum(root->left,targetSum - root->val)) return true;
        if(root->right && hasPathSum(root->right,targetSum - root->val)) return true;
        return false;
    }
};
  • leetcode-105(从前序和中序遍历构造二叉树)
class Solution {
public:

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size() == NULL) return NULL;
        int pos = 0; //中序遍历时根结点的位置
        while(inorder[pos]!=preorder[0]) ++pos;
        vector<int> l_pre,l_in,r_pre,r_in;
        for(int i = 0; i<pos;i++){
            l_pre.push_back(preorder[i+1]);//左子树的前序遍历
            l_in.push_back(inorder[i]);//左子树的中序遍历
        }

        for(int i = pos+1;i<preorder.size();i++){
            r_pre.push_back(preorder[i]);//右子树的前序遍历
            r_in.push_back(inorder[i]);//右子树的中序遍历
        }
        TreeNode *root = new TreeNode(preorder[0]);
        root->left = buildTree(l_pre,l_in);
        root->right = buildTree(r_pre,r_in);
        return root;
    }
};
  • leetcode-222(完全二叉树的节点个数)
 class Solution {
public:
    int countNodes(TreeNode* root) {
        if(root == NULL) return 0;
        return countNodes(root->left)+countNodes(root->right)+1;
    }
};
  • leetcode-剑指Offer 54(二叉搜索树的第k大结点)
 class Solution {
public:
    void in_order(TreeNode *root,vector<int>&ans){
        if(root == NULL) return ;
        in_order(root->left,ans);
        ans.push_back(root->val);
        in_order(root->right,ans);
        return ;
    }
    int kthLargest(TreeNode* root, int k) {
        vector<int> ans;
        in_order(root,ans);
        return ans[ans.size()-k];
        }
};
  • leetcode-剑指Offer 26(树的子结构)
 class Solution {
public:
    bool isMatch(TreeNode *A,TreeNode *B){
        if(B==NULL) return true;
        if(A == NULL)return false;
        if(A->val !=B->val)return false;
        return isMatch(A->left,B->left) && isMatch(A->right,B->right);
    }
    bool isSubStructure(TreeNode* A, TreeNode* B) {
        if(B == NULL) return false;
        if(A == NULL) return false;
        //此时A,B树都不是空树
        if(A->val == B->val && isMatch(A,B)) return true;
        return isSubStructure(A->left,B) || isSubStructure(A->right,B); 
    }
};
  • leetcode-662(二叉树的最大宽度)

  • leetcode-968 (监控的二叉树)(动态规划)


```cpp
class Solution {
public:
    void getDP(TreeNode *root,int dp[2][2]){
        if(root == NULL){
            dp[0][0] = 0;
            dp[0][1] = 10000;
            dp[1][0] = 0;
            dp[1][1] = 10000;
            return ;
        }
        if(root->left == NULL && root->right == NULL ){
            dp[0][0] = 10000;
            dp[0][1] =1;
            dp[1][0] = 0;
            dp[1][1] = 1;
            return ;

        }
        int l[2][2],r[2][2];
        getDP(root->left,l);
        getDP(root->right,r);
        dp[0][0] = min(min(l[0][1]+r[0][0],l[0][0]+r[0][1]),l[0][1]+r[0][1]);
        dp[0][1] = min(min(l[1][0]+r[1][0],l[1][1]+r[1][1]),min(l[1][0]+r[1][1],l[1][1]+r[1][0]))+1;
        dp[1][0] = min(dp[0][0],l[0][0]+r[0][0]);
        dp[1][1] = dp[0][1];
        return ;
    } 
    int minCameraCover(TreeNode* root) {
        int dp[2][2];
        getDP(root,dp);
        return min(dp[0][1],dp[0][0]);
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值