代碼題(28)— 路徑總和系列、二叉樹的所有路徑


  玩樹的題目,十有八九都是遞歸,而遞歸的核心就是不停的DFS到葉結點,然后在回溯回去。在遞歸函數中,當我們遇到葉結點的時候,即沒有左右子結點,那么此時一條完整的路徑已經形成了,我們加上當前的葉結點后存入結果res中,然后回溯。

1、112. 路徑總和

給定一個二叉樹和一個目標和,判斷該樹中是否存在根節點到葉子節點的路徑,這條路徑上所有節點值相加等於目標和。

說明: 葉子節點是指沒有子節點的節點。

示例: 
給定如下二叉樹,以及目標和 sum = 22

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1

  返回 true, 因為存在目標和為 22 的根節點到葉子節點的路徑 5->4->11->2

  這道求二叉樹的路徑需要用深度優先算法DFS的思想來遍歷每一條完整的路徑,也就是利用遞歸不停找子節點的左右子節點,而調用遞歸函數的參數只有當前節點和sum值。首先,如果輸入的是一個空節點,則直接返回false,如果如果輸入的只有一個根節點,則比較當前根節點的值和參數sum值是否相同,若相同,返回true,否則false。 這個條件也是遞歸的終止條件。下面我們就要開始遞歸了,由於函數的返回值是Ture/False,我們可以同時兩個方向一起遞歸,中間用或||連接,只要有一個是True,整個結果就是True。遞歸左右節點時,這時候的sum值應該是原sum值減去當前節點的值。

/**
 * 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 == nullptr || sum<=0)
            return false;
        if(root->left==nullptr && root->right==nullptr && root->val == sum)
            return true;
        return hasPathSum(root->left,sum-root->val) || hasPathSum(root->right, sum-root->val);
        
    }
    
};

2、113. 路徑總和 II

給定一個二叉樹和一個目標和,找到所有從根節點到葉子節點路徑總和等於給定目標和的路徑。

說明: 葉子節點是指沒有子節點的節點。

示例:
給定如下二叉樹,以及目標和 sum = 22

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1

返回:

[
   [5,4,11,2],
   [5,8,4,5]
]

  還是需要用深度優先搜索DFS,只不過數據結構相對復雜一點,需要用到二維的vector,而且每當DFS搜索到新節點時,都要保存該節點。而且每當找出一條路徑之后,都將這個保存為一維vector的路徑保存到最終結果二位vector中。並且,每當DFS搜索到子節點,發現不是路徑和時,返回上一個結點時,需要把該節點從一維vector中移除。

/**
 * 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<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> res;
        if(root == nullptr)
            return res;
        vector<int> temp;
        findPath(root,sum,temp,res);
        return res;
    }
    void findPath(TreeNode* root,int sum,vector<int> &temp,vector<vector<int>> &res)
    {
        if(root == nullptr)
            return;
        temp.push_back(root->val);
        sum -= root->val;
        if(root->left==nullptr && root->right==nullptr && sum==0)
        {
            res.push_back(temp);
        }
        else
        {
            findPath(root->left,sum,temp,res);
            findPath(root->right,sum,temp,res);
        }
        temp.pop_back();
    }
};

3、 437. 路徑總和 III

給定一個二叉樹,它的每個結點都存放着一個整數值。

找出路徑和等於給定數值的路徑總數。

路徑不需要從根節點開始,也不需要在葉子節點結束,但是路徑方向必須是向下的(只能從父節點到子節點)。

二叉樹不超過1000個節點,且節點數值范圍是 [-1000000,1000000] 的整數。

示例:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

返回 3。和等於 8 的路徑有:

1.  5 -> 3
2.  5 -> 2 -> 1
3.  -3 -> 11

  這道題讓我們求二叉樹的路徑的和等於一個給定值,說明了這條路徑不必要從根節點開始,可以是中間的任意一段,而且二叉樹的節點值也是有正有負。那么我們可以用遞歸來做,相當於先序遍歷二叉樹,對於每一個節點都有記錄了一條從根節點到當前節點到路徑,同時用一個變量curSum記錄路徑節點總和,然后我們看curSum和sum是否相等,相等的話結果res加1,不等的話我們來繼續查看子路徑和有沒有滿足題意的,做法就是每次去掉一個節點,看路徑和是否等於給定值,注意最后必須留一個節點,不能全去掉了,因為如果全去掉了,路徑之和為0,而如果假如給定值剛好為0的話就會有問題。

/**
 * 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:
    int pathSum(TreeNode* root, int sum) {
        int res=0;
        if(root==nullptr)
            return res;
        vector<TreeNode*> temp;
        pathAll(root,sum,0,temp,res);
        return res;
    }
    void pathAll(TreeNode* root, int sum, int cursum, vector<TreeNode*> &temp, int &res)
    {
        if(root==nullptr)
            return;
        temp.push_back(root);
        cursum += root->val;
        if(cursum==sum)
            res++;
        int t = cursum;
        for(int i=0;i<temp.size()-1;++i) //要保留一個值,如果sum=0 
        {
            t -= temp[i]->val;
            if(t==sum)
                res++;
        }
        pathAll(root->left, sum, cursum,temp,res);
        pathAll(root->right, sum, cursum, temp, res);
        temp.pop_back();
    }
    
};

4、257. 二叉樹的所有路徑 

給定一個二叉樹,返回所有從根節點到葉子節點的路徑。

說明: 葉子節點是指沒有子節點的節點。

示例:

輸入:

   1
 /   \
2     3
 \
  5

輸出: ["1->2->5", "1->3"]

解釋: 所有根節點到葉子節點的路徑為: 1->2->5, 1->3

  這道題給我們一個二叉樹,讓我們返回所有根到葉節點的路徑,跟之前那道Path Sum II很類似,比那道稍微簡單一些,不需要計算路徑和,只需要無腦返回所有的路徑即可,那么思路還是用遞歸來解,博主之前就強調過,玩樹的題目,十有八九都是遞歸,而遞歸的核心就是不停的DFS到葉結點,然后在回溯回去。在遞歸函數中,當我們遇到葉結點的時候,即沒有左右子結點,那么此時一條完整的路徑已經形成了,我們加上當前的葉結點后存入結果res中,然后回溯。注意這里結果res需要reference,而out是不需要引用的,不然回溯回去還要刪除新添加的結點,很麻煩。為了減少判斷空結點的步驟,我們在調用遞歸函數之前都檢驗一下非空即可,代碼而很簡潔,參見如下:

/**
 * 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==nullptr)
            return res;
        string temp;
        binary(root, temp, res);
        return res;
        
    }
    void binary(TreeNode* root, string temp, vector<string> &res )
    {
        if(!root->left && !root->right)
            res.push_back(temp+to_string(root->val));
        if(root->left)
        {
            binary(root->left, temp+to_string(root->val)+"->",res);
        }
        if(root->right)
        {
            binary(root->right, temp+to_string(root->val)+"->",res);
        }
    }
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM