1. 程式人生 > >LeetCode Easy 437 路徑之和III Python

LeetCode Easy 437 路徑之和III Python

    Disscusion Method

    演算法:雜湊表+DFS

    思路

        首先要想暴力解法是怎樣進行的

            在暴力解法中,也就是下面我的那種解法,遍歷每一個節點,在每一個節點的位置,還要向下遍歷其他的每一個節點

        但是這樣的話在遍歷的過程中有很多遍歷是重複的                         

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

            比如遍歷到5的時候。會有5->3->3,3->3,10->5->3->3,其實就是一條路徑,只不過每次的節點不一樣罷了。

        但是用暴力解法遍歷的話會重複遍歷很多次,例如以10開頭的時候遍歷了10->5->3->3,後面又會以5開頭遍歷5->3->3

            所以首先要想的是,如何將一條路徑拆成多條,因為根據題意,答案的路徑不一定非要是從root開始的,所以在遍歷

        過程中形成的path路徑,能不能將他拆開?比如從10開始遍歷,遍歷路徑10->5->3,能不能將其拆成10,5->3?

            答案當然是可以的,因為可以看做是從10出發了3層到達的這裡,其實第一層10的時候就可以記錄下來這個10,然後到

        10->5->3的時候,再"減去"前面單個節點10的情況就好了。

            所以這種解法就是基於這樣的思想在遍歷所有節點。並且聯想TwoSum中的做法,用雜湊表來儲存要找的那個"加數"

            注意到本題中,要求的解的路徑其實可以看做是一整條路徑中的一部分,然後再根據上面講到的將一條路徑拆成多個

        部分組成。那麼就可以設定一個雜湊表,record,由record記錄當前路徑和的個數,{curr_sum:counter},

            由curr_sum來記錄遍歷到當前節點的路徑和,如果一條目標路徑在這條路徑中,那麼就可以按上述的拆分路徑的方法求得

        當前子路徑的前序路徑和,即prefix_sum = curr_sum - target,然後在record中查詢prefix_sum的個數。如果record

        中記錄了這個prefix_sum,那麼就表明當前路徑中包含解,並且prefix_sum有幾個,這樣的路徑就有幾個

            如:10->5->3,target = 8,curr_sum - 8 = 10,而前面記錄下來的record[10]=1,就說明有1條包含答案的路徑,

        當然了,如果前面record[10]=n,那麼就說明走到了10->5->3時,在這條路徑上符合答案的路徑就有n條,result += n

            所以在遍歷的過程中應該record[curr_sum] += 1,記錄下來curr_sum的個數,curr_sum在後面層數的遞迴中就相當於

        是prefix_sum了。

            所以根據以上思路dfs前序遍歷二叉樹,並且要注意的是當前節點的左右子樹遍歷完之後,要record[curr_sum] -= 1

            因為記錄record[curr_sum] -= 1是為了記錄當前路徑和作為prefix的話有多少個,當前節點的子樹遍歷完之後,應該

        彈出當前節點的路徑和,就像回溯的時候一樣。比如還是10->5->3這裡,記錄了18後,遍歷完這個③的節點,將18的個數減1,

        避免遞迴到⑩的右子樹時,可能某個位置需要前面是18,但是誤認為左子樹的③這裡記錄的18是符合要求的,這樣會將路徑

        計算錯。

            ❗️❗️❗️所以要明確,record[curr_sum]記錄的是當前路徑上有多少個子字首路徑的和是curr_sum,或者從子遞迴中看,應該叫

        record[prefix_sum]

    複雜度分析

        時間:ON,遍歷一遍所有節點

        空間:ON,雜湊表空間

def pathSum(self, root, sum):
    self.result = 0

    def dfs(root, record, curr_sum):
        if root == None:
            return
        curr_sum += root.val
        prefix_sum = curr_sum - sum
        if prefix_sum in record:
            self.result += record[prefix_sum]
        record.setdefault(curr_sum, 0)
        record[curr_sum] += 1
        dfs(root.left, record, curr_sum)
        dfs(root.right, record, curr_sum)
        record[curr_sum] -= 1

    dfs(root, {0: 1}, 0)
    return self.result



def pathSum1(self, root, sum):
    """
    My Brute Force Method
    演算法:暴力
    思路:
        Do as they say
        遍歷所有可能,dfs遍歷每個節點,在每個節點位置向下深度遍歷calculateSum()計算是否構成題解
        這裡主要是會重複計算一些路徑和,導致時間的浪費
    複雜度分析:
        時間:ON2
        空間:ON2
    """
    self.counter = 0
    def calculateSum(root,path_sum):
        if root == None :
            return
        path_sum += root.val
        if path_sum == sum:
            self.counter += 1
        calculateSum(root.left,path_sum)
        calculateSum(root.right,path_sum)
    def dfs(root):
        if root == None:
            return
        calculateSum(root,0)
        dfs(root.left)
        dfs(root.right)
    dfs(root)
    return self.counter