LeetCode相关典型题解合集——树

所有的题型目录在下面的链接
LeetCode相关典型题解合集(两百多道题)



一、递归

104. 二叉树的最大深度

class Solution {
public:
    //递归写法
    int maxDepth(TreeNode* root) {
        if(root==NULL){
            return 0;
        }
        int l=maxDepth(root->left)+1;
        int r=maxDepth(root->right)+1;
        return l>r?l:r;
    }
};

110.平衡二叉树

class Solution {
public:
    int GetHeight(TreeNode *node){//求某一个节点的高度
        if(node==nullptr){
            return 0;
        }
        int left=GetHeight(node->left)+1;
        int right=GetHeight(node->right)+1;
        return max(left,right);
    }
    bool isBalanced(TreeNode* root) {
        //1、自顶向下的解法
        if(root==nullptr){
            return true;
        }
        if(abs(GetHeight(root->left)-GetHeight(root->right))>1){
            return false;
        }
        return isBalanced(root->left)&&isBalanced(root->right);
    }
};

543.二叉树的直径

class Solution {
public:
int max=0;
    int diameterOfBinaryTree(TreeNode* root) {
        //自己的办法,思路:跟深度有关。每个节点左右子树高度和的最大值
        if(root!=nullptr){
            deep(root);
            return max;
        }
        return 0;
    }
    int deep(TreeNode *node){
        if(node==nullptr){
            return 0;
        }
        int l=deep(node->left);
        int r=deep(node->right);
        if(l+r>max){
            max=l+r;
        }
        return l>r?l+1:r+1;
    }
};

226.翻转二叉树

class Solution {
public:
    TreeNode *temp=new TreeNode();
    TreeNode* invertTree(TreeNode* root) {
        //递归法,后序遍历
        if(root==nullptr){
            return nullptr;
        }
        invertTree(root->left);
        invertTree(root->right);
        temp=root->left;
        root->left=root->right;
        root->right=temp;
        return root;
    }
};

617.合并二叉树

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if(t1==nullptr){
            return t2;
        }
        if(t2==nullptr){
            return t1;
        }
        t1->val+=t2->val;
        //记住,这个递归函数的返回值是节点,所以下面的可以这样理解:
        //t1的左节点返回的是什么,具体要看上面两个if的判断
        //比如t1为空,则说明1树的节点没东西,就两种情况:2树对应的节点有或者没,都可以返回t2的节点
        t1->left=mergeTrees(t1->left,t2->left);
        t1->right=mergeTrees(t1->right,t2->right);
        return t1;
    }
};

112. 路径总和(判断路径和是否等于一个数)

class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if(root==nullptr){
            return false;
        }
        if(root->left==nullptr&&root->right==nullptr){
            return root->val==sum;
        }
        //如果要返回的是节点本身,而不是长度等变量,就是左子树||右子树,
        return hasPathSum(root->left,sum-root->val)||hasPathSum(root->right,sum-root->val);
    }
};

437. 统计路径和等于一个数的路径数量

class Solution {
public:
    //最简单的递归算法,可以改进很多
    int count=0;
    int pathSum(TreeNode* root, int sum) {
        if(root==nullptr){
            return 0;
        }
        countPath(root,sum);
        pathSum(root->left,sum);
        pathSum(root->right,sum);
        return count;
    }
    void countPath(TreeNode *node,int sum){
        if(node==nullptr){
            return ;
        }
        sum-=node->val;
        if(sum==0){
            count++;
        }
        countPath(node->left,sum);
        countPath(node->right,sum);
    }
};

572. 另一个数的子树

class Solution {
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(s==nullptr){
            return  false;
        }
        return isEqual(s,t)||isSubtree(s->left,t)||isSubtree(s->right,t);
    }
    bool isEqual(TreeNode *l,TreeNode*r){
         if(l==nullptr&&r==nullptr){
            return true;
        }
        if(l==nullptr||r==nullptr){
            return false;
        }
        if(l->val!=r->val){
            return false;
        }
        //如果左子树相等还要看右子树是否相等才能判断是否是相等
        return isEqual(l->left,r->left)&&isEqual(l->right,r->right);
    }
};

101. 树的对称

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        return isEqual(root,root);
    }
    bool isEqual(TreeNode *l,TreeNode *r){
        //子节点要么都不为空,要么都为空
        if(l==nullptr&&r==nullptr){
            return true;
        }
        if(l==nullptr||r==nullptr){
            return false;
        }
        return (l->val==r->val)&&isEqual(l->left,r->right)&&isEqual(l->right,r->left);
    }
};

111. 最小路径(最小深度)

class Solution {
public:
    int minDepth(TreeNode* root) {
        //这个方法时间终极爆炸!
        if(root==nullptr){
            return 0;
        }
        int l=minDepth(root->left)+1;
        int r=minDepth(root->right)+1;
        if(l==1||r==1){ 
            return l>r?l:r;
        }else{
            return l<r?l:r;
        }

    }
};

404. 统计左叶子节点的和

class Solution {
public:
    int sum=0;
    int sumOfLeftLeaves(TreeNode* root) {
        //递归,简单的方法
        if(root==nullptr){
            return 0;
        }
        //判断是否是左叶子的方法
        if(root->left!=nullptr&&root->left->left==nullptr&&root->left->right==nullptr){
            sum+=root->left->val;
        }
        sumOfLeftLeaves(root->left);
        sumOfLeftLeaves(root->right);
        return sum;
    }
};

687. 相同节点值的最大路径长度

class Solution {
public:
    //递归的写法,一共是两种情况
    //1、左右子树依次递归下去
    //2、一个子树的节点和根都相同
    int max=0;
    int longestUnivaluePath(TreeNode* root) {
        GetMax(root);
        return max;
    }
    int GetMax(TreeNode *node){
        if(node==nullptr){
            return 0;
        }
        /*int intervalMax=0;
        int left=GetMax(node->left);
        int right=GetMax(node->right);
        //1种情况
        if(node->left!=nullptr&&node->left->val==node->val){
            intervalMax=left+1;
        }
        if(node->right!=nullptr&&node->right->val==node->val){
            intervalMax=intervalMax>left?intervalMax:right+1;
        }
        int max=max>intervalMax?max:intervalMax;
        //2
        if(node->left!=nullptr&&node->right!=nullptr&&node->left->val==node->val&&node->right->val==node->val){
            max=max>(left+right+2)?max:left+right+2;
        }
        return intervalMax;*/
        int intLeft=0;
        int intRight=0;
        int left=GetMax(node->left);
        int right=GetMax(node->right);
        if(node->left!=nullptr&&node->val==node->left->val){
            intLeft=left+1;
        }
        if(node->right!=nullptr&&node->val==node->right->val){
            intRight=right+1;
        }
        max=max>intRight+intLeft?max:intRight+intLeft;
        return intLeft>intRight?intLeft:intRight;
    }
};

337. 间隔遍历(打家劫舍三)

class Solution {
public:
    //本质上就是间隔遍历
    //把问题直接简化成两个部分:①偷父节点②不偷父节点
    int rob(TreeNode* root) {
        if(root==nullptr){
            return 0;
        }
        if(root->left==nullptr&&root->right==nullptr){
            return root->val;
        }
        //偷父节点的
        int cash1=root->val;
        int cash2=0;
        if(root->left!=nullptr){
            cash1+=rob(root->left->left)+rob(root->left->right);
        }
        if(root->right!=nullptr){
            cash1+=rob(root->right->left)+rob(root->right->right);
        }
        //不偷父节点
        cash2+=rob(root->left)+rob(root->right);
        return cash1>cash2?cash1:cash2;
    }
};

671. 找出二叉树中第二小的节点

class Solution {
public:
    
    int findSecondMinimumValue(TreeNode* root) {
        //①暴力破解
        /*vector<int> sequence;
        construct_vector(root,sequence);
        sort(sequence.begin(),sequence.end(),less<int>());
        int min=sequence.front();
        int sec_min=0;
        if(sequence.empty()==true||sequence.size()==1){
            return -1;
        }else{
            for(int i=0;i<sequence.size();i++){
                if(sequence[i]>min){
                    sec_min=sequence[i];
                    break;
                }
            }   
        }   
        if(sec_min==0){
            return -1;
        }
        return sec_min;*/

        /*************************************************************************************/
        
        //根据这颗树的特点来做
        //注意!这道题的最小节点肯定是根节点,但是第二小的结点不确定,自己想一下就知道了,所以必须遍历所有的结点。
        return get_val(root,root->val);
    }

    int get_val(TreeNode *root,int n){
        if(root==nullptr){
            return -1;
        }
        if(root->val>n){
            return root->val;
        }
        int left=get_val(root->left,n);
        int right=get_val(root->right,n);
        if(left>n&&right>n){
            return left>right?right:left;
        }
        return left>right?left:right;
    }



    void construct_vector(TreeNode *root,vector<int> &vec){
        if(root){
           construct_vector(root->left,vec);
            vec.push_back(root->val);
            construct_vector(root->right,vec);
        }
        
    }
    
};

第二种方法
1.没有必要记录最小的值,因为最小的一定是根结点。 2.递归找到比根结点大的值时可以立即返回,不用再遍历当前节点下面的子节点,因为子节点的值不可能比它小。

class Solution {
public:
    int firstbigger(TreeNode* root, int val) {
        if (!root) return -1;
        if (root -> val > val) return root -> val;
        int left = firstbigger(root -> left, val);
        int right = firstbigger(root -> right, val);
        if (left < 0) return right;
        if (right < 0) return left;
        return min(left, right);
    }
    int findSecondMinimumValue(TreeNode* root) {
        return firstbigger(root, root -> val);
    }
};

二、层序遍历

637.二叉树每层节点的平均数

class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        queue<TreeNode*> q;
        vector<double> ves;
        q.push(root);
        double total=0;
        if(root==NULL){
            return ves;
        }
        while(!q.empty()){
            int length =q.size();
            total=0;
            for(int i=0;i<length;i++){
                TreeNode *p=q.front();
                total+=p->val;
                q.pop();
                if(p->left!=NULL){
                    q.push(p->left);
                }
                if(p->right!=NULL){
                    q.push(p->right);
                }
            }
            ves.push_back(total/length);
            
        }
        return ves;
    }
};

513. 找到树左下角的值

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> q;
        vector<int> vec;
        q.push(root);
        int temp;
        while(!q.empty()){
            int length=q.size(); 
            if(!vec.empty()){
                    vec.clear();
                }
            for(int i=0;i<length;i++){
                 
                TreeNode *p=q.front();
                vec.push_back(p->val);
                q.pop();
                if(p->left!=NULL){
                    q.push(p->left);
                    
                }
                if(p->right!=NULL){
                    q.push(p->right);
                }
            }
            
        }
        return vec.front();
    }
};

三、前中后序遍历(非递归)

144. 非递归实现二叉树的前序遍历

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> sequence;
        stack<TreeNode* > s;
        while(root||!s.empty()){
            while(root){
                sequence.push_back(root->val);
                s.push(root);
                root=root->left;
            }
            if(!s.empty()){
                root=s.top();
                s.pop();
                root=root->right;
            }
        }
        return sequence;
    }
};

94. 非递归实现二叉树的中序遍历

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> sequence;
        stack<TreeNode*> s;
        while(root||!s.empty()){
            while(root){
                s.push(root);
                root=root->left;
            }
            if(!s.empty()){
                root=s.top();
                sequence.push_back(root->val);
                s.pop();
                root=root->right;
            }
        }
        return sequence;
    }
};

145. 非递归实现二叉树的后序遍历

高频面试题!

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> sequence;
        stack<TreeNode*> s;
        //用来记录上一个节点
        TreeNode *pre=nullptr;
        while(root||!s.empty()){
            while(root){
                s.push(root);
                root=root->left;
            }
            root=s.top();
            //防止此节点的右孩子重复访问
            if(!root->right||root->right==pre){
                sequence.push_back(root->val);
                s.pop();
                pre=root;
                root=nullptr;

            }else{
                root=root->right;
            }
        }
        return sequence;
    }
};

四、BST(二叉搜索树)

669. 修剪二叉查找树

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if(root==nullptr){
            return root;
        }
        //如果根节点的值小于low,则说明看右子树的了,因为左子树的孩子节点都比根节点小
        else if(root->val<low){
            return trimBST(root->right,low,high);
        }
        //跟上面同理
        else if(root->val>high){
            return trimBST(root->left,low,high);
        }
        root->left=trimBST(root->left,low,high);
        root->right=trimBST(root->right,low,high);
        return root;
    }
};

230. 二叉搜索树中第K小的元素

class Solution {
public:
        int m;
        int count=0;
    int kthSmallest(TreeNode* root, int k) {
        if(root){
            kthSmallest(root->left,k);
            count++;
            if(count==k){
                m=root->val;
            }
            kthSmallest(root->right,k);
        }
        return m;
    }

};

235. 二叉搜索树的最近公共祖先

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

236. 二叉树的最近公共祖先

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

108. 将有序数组转换为二叉搜索树

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

109. 有序链表转换二叉搜索树

class Solution {
public:
    TreeNode* sortedListToBST(ListNode* head) {
        if(!head){
            return nullptr;
        }
        else if(!head->next){
            return new TreeNode(head->val);
        }
        ListNode *pre=head;
        ListNode *p=head;
        ListNode *q=head;
        while(q!=nullptr&&q->next!=nullptr){
            p=p->next;
            q=q->next->next;
        }
        while(pre->next!=p){
            pre=pre->next;
        }
        pre->next=nullptr;
        TreeNode *root=new TreeNode(p->val);
        root->left=sortedListToBST(head);
        root->right=sortedListToBST(p->next);
        return root;
    }
};

653. 在二叉查找树中寻找两个节点,使它们的和为一个给定值

class Solution {
public:
    vector<int> sequence;
    bool findTarget(TreeNode* root, int k) {
        mid_order(root,sequence);
        int l=0;
        int r=sequence.size()-1;
        while(l<r){
            if(sequence[l]+sequence[r]>k){
                r--;
            }
            else if(sequence[l]+sequence[r]<k){
                l++;
            }else if(sequence[l]+sequence[r]==k){
                return true;
            }
        }
        return false;
    }

    void mid_order(TreeNode *root,vector<int> &vec){
        if(root){
            mid_order(root->left,vec);
            vec.push_back(root->val);
            mid_order(root->right,vec);
        }
    }
};

530. 在二叉查找树中查找两个节点之差的最小绝对值

class Solution {
public:
    vector<int> sequence;
    int getMinimumDifference(TreeNode* root) {
        mid_order(root,sequence);
        int min=abs(sequence[1]-sequence[0]);
        //注意是中序遍历是有序递增的!
        for(int i=0;i<sequence.size()-1;i++){
            /*for(int j=0;j<sequence.size();j++){
                if(i!=j&&abs(sequence[i]-sequence[j])<min){
                    min=abs(sequence[i]-sequence[j]);
                }
            }*/
            if(abs(sequence[i]-sequence[i+1])<min){
                min=abs(sequence[i]-sequence[i+1]);
            }
        }
        return min;
    }
    void mid_order(TreeNode *root,vector<int>& vec){
        if(root){
            mid_order(root->left,vec);
            vec.push_back(root->val);
            mid_order(root->right,vec);
        }
    }
};

501. 寻找二叉查找树中出现次数最多的值

class Solution {
public:
    //最麻烦的,开辟额外空间的写法,用一个vector存储中序遍历的值,一个返回众数的值
    vector<int> sequence;
    vector<int> findMode(TreeNode* root) {
        vector<int> res;
        int count=1;
        int max_count=1;
        int order;
        mid_order(root,sequence);
        if(root==nullptr){
            return {};
        }
        for(int i=0;i<sequence.size()-1;i++){
            if(sequence[i]==sequence[i+1]){
                count++;
            }else{
                count=1;
            }
            if(count>max_count){
                max_count=count;
                order=i;
                res.clear();
                res.push_back(sequence[order]);
            }
            else if(count==max_count){
                max_count=count;
                order=i;
                res.push_back(sequence[order]);
            }
        }
        //注意如果数组都不相同,返回空vector,return {}
        if(max_count==1){
            return sequence;
        }
        return res;
    }
    void mid_order(TreeNode*root,vector<int> &vec){
        if(root){
            mid_order(root->left,vec);
            vec.push_back(root->val);
            mid_order(root->right,vec);
        }
    }
};

五、trie(前缀树或字典树)

Trie,又称前缀树或字典树,用于判断字符串是否存在或者是否具有某种字符串前缀。

208. 实现一个 Trie

677. 实现一个 Trie,用来求前缀和

总结

提示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值