1. 程式人生 > >34 二叉樹中和為某一值的路徑(舉例讓抽象問題具體化)

34 二叉樹中和為某一值的路徑(舉例讓抽象問題具體化)

fin emp 改變 步驟 pat 用例 遞歸 ret nodes

題目描述:

輸入一顆二叉樹的跟節點和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。

(註意: 在返回值的list中,數組長度大的數組靠前)

測試用例:

功能測試(二叉樹中有一條或者多條符合要求的路徑;二叉樹中沒有符合要求的路徑;完全二叉樹,只有左子節點或者右子節點

特殊輸入測試(空樹nullptr)

解題思路:

1)規律:當用前序遍歷的方式訪問到某一個節點時,把該節點添加到路徑上,並累加該節點的值。

如果該節點為葉子節點,並且路徑中的值的和剛好等於輸入的整數,則當前路徑符合要求,打印該路徑。

如果當前節點不是葉子節點,則繼續訪問它的子節點。當前節點訪問結束後,遞歸函數將自動回到它的父節點。因此,我們在函數退出之前要在路徑上刪除當前節點減去當前節點的值,以確保返回父節點時路徑剛好是從根節點到父節點。

( 因為int值有正有負,所以不加到最後一個節點(葉子節點)無法判斷該路徑是否符合。即,要遍歷所有路徑。)

實現一:牛客通過,但是並沒有考慮題目中 “ 在返回值的list中,數組長度大的數組靠前 ”

class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        
        if(root==nullptr)return result;
        
        FindPathCore( root, expectNumber);
        return result;

        
    }
    void FindPathCore(TreeNode* root,int expectNumber){
        TreeNode* pNode = root;
        pathNodes.push_back(root->val);
        sum += root->val;
        
        if(sum==expectNumber && pNode->left==nullptr && pNode->right==nullptr){
            //到達根節點
            result.push_back(pathNodes);
        }
        
        //不是葉子節點
        if(pNode->left){//左子樹非空
            FindPathCore(pNode->left,expectNumber);
        }
        
        if(pNode->right){//右子樹非空
            FindPathCore(pNode->right,expectNumber);
        }
        
        //重要的部分!!!
        //葉子節點。在返回父節點前,在路徑上刪除當前節點。 
        pathNodes.pop_back();
        sum -= root->val;
    }
private:
    int sum = 0; //用於存儲和
    vector<vector<int> > result; //用於存儲最終的結果
    vector<int> pathNodes; //用於存儲每條路徑
};

2)非遞歸版本

1.按先序遍歷把當前節點cur的左孩子依次入棧同時保存當前節點,每次更新當前路徑的和sum;
2.判斷當前節點是否是葉子節點以及sum是否等於expectNumber,如果是,把當前路徑放入結果中。
3.遇到葉子節點cur更新為NULL,此時看棧頂元素,如果棧頂元素的把棧頂元素保存在last變量中,同時彈出棧頂元素,當期路徑中棧頂元素彈出,sum減掉棧頂元素,這一步驟不更改cur的值;
4.如果步驟3中的棧頂元素的右孩子存在且右孩子之前沒有遍歷過,當前節點cur更新為棧頂的右孩子,此時改變cur=NULL的情況。

class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root, int expectNumber) {
        stack<TreeNode*> s;
        vector<int> v;
        vector<vector<int> > res;
        while (root || !s.empty()){
            while (root){ //尋找一個路徑,壓入棧
                s.push(root); v.push_back(root->val); expectNumber -= root->val;
                //能左就左,否則向右
                root = root->left ? root->left : root->right;
            }
            root = s.top(); //指向棧頂,即葉子節點
            if (expectNumber == 0 && root->left == NULL && root->right == NULL)
                res.push_back(v);
            s.pop(); v.pop_back(); expectNumber += root->val;
            //右子數沒遍歷就遍歷,如果遍歷就強迫出棧
            if (!s.empty() && s.top()->left == root) 
                root = s.top()->right;
            else
                root = NULL;//強迫出棧
        }
        return res;
    }
};

  

  

34 二叉樹中和為某一值的路徑(舉例讓抽象問題具體化)