leetcode題解(二叉樹和遞歸問題)

這篇博客咱們主要來看二叉樹和二叉樹問題中使用遞歸來解決問題的思路。這類問題有時思路很簡單,這是由於二叉樹具備自然的遞歸結構,因此咱們使用遞歸的解法解決二叉樹有關的問題就變得很是明顯。node

二叉樹自然的遞歸結構

  • 語義
  • 終止條件
  • 遞歸過程

例子

二叉樹前序遍歷

//前序遍歷node節點
void preorder(TreeNode * node){
	if (node == NULL){ 
    	return; //終止條件
    }
    
    cout << node -> val;
    preorder(node -> left);
    preorder(node -> right);//遞歸過程
}

複製代碼

二叉樹查找某個節點

bool contain(Node *node, key key){
	if (node == NULL)
    	return false;
        
    if (key == node->key)
    	return true;
        
    if( contain(node -> left,key) || contain(node -> right, key))
    	return true;
        
    return false;
}

複製代碼

刪除一顆二叉樹

void destroy(Node * node){
	if(node == NULL)
    	return;
    destroy(node->left);
    destroy(node->right);
    
    delete node;
    count --;
}

複製代碼

leetcode 104. 二叉樹的最大深度

paste image

class Solution {
public:
    //求節點root的深度
    int maxDepth(TreeNode* root) {
        //終止條件
        if(root == NULL){ 
            return 0;
        }
        
        return 1 + max(maxDepth(root -> left), maxDepth(root -> right));
        
    }
};
複製代碼

類似問題

leetcode 111

一個簡單的二叉樹問題引起的血案

leetcode 226. 翻轉二叉樹

paste image

代碼實現

/// Definition for a binary tree node.
    struct TreeNode {
        int val;
        TreeNode *left;
        TreeNode *right;
        TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    };
    
    class Solution {
    public:
        TreeNode* invertTree(TreeNode* root) {
    
            if ( root == NULL ) {
                return NULL;
            }
    
            invertTree( root->left );
            invertTree( root->right );
            swap ( root->left, root->right );
    
            return root;
        }
    };
    
複製代碼

類似問題

leetcode 100

leetcode 101

leetcode 222

leetcode 110


注意遞歸的終止條件

有的時候遞歸的終止條件是存在陷阱的。ios

leetcode 112. 路徑總和

paste image

解題思路

採起遞歸來解決這個問題,咱們能夠從頭結點開始,向它的左右孩子節點尋找sum-根節點的值,不斷向下尋找。這道題陷阱在於終止條件不是node == NULL。bash

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if (root == NULL){
            return false;
        }
        
        //爲葉子節點
        if (root -> left == NULL && root -> right == NULL){
            return root -> val == sum;
        }
        
        return hasPathSum(root -> left, sum - root -> val) || hasPathSum(root -> right, sum - root -> val);
        
        
        return false;
        
    }
}; 
複製代碼

定義遞歸問題

咱們如何使用遞歸的返回值來解決問題。 函數的語義很重要微信

leetcode 257. 二叉樹的全部路徑

paste image

思路

對於每個節點,就是該節點的值加上「->」再加上左子樹的路徑字符串和右子樹路徑字符串。當到達葉節點時,將字符串加入結果集。函數

實現

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> res;
        
        if (root == NULL){
            return res;
        }
        
        if (root -> left == NULL && root -> right == NULL){
            res.push_back(to_string(root -> val));
            return res;
        }
        
        vector<string> lefts = binaryTreePaths(root -> left);
        
        for(int i = 0; i < lefts.size(); i++){
            res.push_back(to_string(root -> val) + "->" + lefts[i]);
        }
        
        
        vector<string> rights = binaryTreePaths(root -> right);
        
        for(int i = 0; i < rights.size(); i++){
            res.push_back(to_string(root -> val) + "->" + rights[i]);
        }
        
        return res;
        
    }
};

複製代碼

類似問題

leetcode 113

leetcode 129


稍複雜的遞歸邏輯

leetcode 437. 路徑總和 III

paste image

解題思路

猛地一看這個描述,和咱們以前的Path Sum是同樣的。可是區別在於咱們對於路徑的定義不必定要起始於根節點,終止於葉子結點,路徑能夠從任意節點開始,可是隻能是向下走的。ui

paste image

在一個節點上要經過三個部分得到答案,第一個部分看看有沒有一條路徑,它包含node這個節點,而且它的和爲sum,這個路徑咱們進入findPath這個子過程,這個子過程自己又是一個遞歸函數。另外的兩部分就是要在node的左右子樹去尋找沒有這個ndoe節點的值,有沒有這樣的路徑,他們的和仍然爲sum,這件事就是咱們PathSum這個函數所作的。在node->left和node->right分別調用PathSum的過程當中,他們也會調用findPath來求解。spa

代碼實現

#include <iostream>
    
    using namespace std;
    
    // Definition for a binary tree node.
    struct TreeNode {
        int val;
        TreeNode *left;
        TreeNode *right;
        TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    };
    
    class Solution {
    
    public:
        // 在以root爲根節點的二叉樹中,尋找和爲sum的路徑,返回這樣的路徑個數
        int pathSum(TreeNode* root, int sum) {
    
            if ( root == NULL) {
                return 0;
            }
    
            int res = findPath( root, sum );
            res += pathSum( root->left,  sum );
            res += pathSum( root->right, sum );
    
            return res;
        }
    
    private:
    
        // 在以node爲根節點的二叉樹中,尋找包含node的路徑,和爲sum
        // 返回這樣的路徑個數
        int findPath( TreeNode* node, int num){
    
            if ( node == NULL ) {
                return 0;
            }
    
            int res = 0;
            if ( node->val == num ) {
                res += 1;
            }
    
            res += findPath( node->left, num - node->val );
            res += findPath( node->right, num - node->val );
    
            return res;
        }
    };
    
複製代碼

二分搜索樹中的問題

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

paste image

思路

二分搜索樹:
每一個節點的鍵值大於左孩子
每一個節點的鍵值小於右孩子
以左右孩子爲跟的子樹仍爲二分搜索樹3d

若是咱們給的p,q節點都小於node節點,那麼他們最近的公共祖先必定在node左邊。若是咱們給的p,q節點都大於node節點,那麼他們最近的公共祖先必定在ndoe右邊。若是一小一大,那麼node必定是最近的公衆祖先。code

代碼實現

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        assert(p != NULL && q != NULL);
        
        if (root == NULL){
            return NULL;
        }
        
        if ((root -> val > p -> val) && (root -> val > q -> val))
            return lowestCommonAncestor(root -> left, p, q);
        
        if ((root -> val < p -> val) && (root -> val < q -> val))
            return lowestCommonAncestor(root -> right, p, q);
        
        //p 與q在root的兩側, 則root必爲公共祖先,包含p爲q的祖先
        return root;
    }
};

複製代碼

類似問題

leetcode 98

leetcode 450

leetcode 108

  • 中序遍歷

leetcode 230

leetcode 236



-------------------------華麗的分割線--------------------cdn

看完的朋友能夠點個喜歡/關注,您的支持是對我最大的鼓勵。

我的博客番茄技術小棧掘金主頁

想了解更多,歡迎關注個人微信公衆號:番茄技術小棧

番茄技術小棧
相關文章
相關標籤/搜索