程序员面试金典 4.12

Paths with Sum:在一个二叉树中计算路径上节点和等于给定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:
    int pathSum(TreeNode* root, int sum) {
        if(root == nullptr) return 0;
        int rootCnt = pathCnt(root, sum, 0);
        int leftCnt = pathSum(root->left, sum);
        int rightCnt = pathSum(root->right, sum);
        return rootCnt + leftCnt + rightCnt;
    }
private:
    int pathCnt(TreeNode* root, const int sum, int part)
    {
        int paths = 0;
        if(root == nullptr) return 0;
        part += root->val;
        if(part == sum) paths++;
        paths += pathCnt(root->left, sum, part);
        paths += pathCnt(root->right, sum, part);
        return paths;
    }
};

算法的复杂度计算会复杂一些,考虑每个节点被访问了多少次。如果是完全二叉树,在第1层遍历N - 1个节点,第2层遍历2(N - 1)个几点,第3层遍历4(N - 3)个节点,通向公式为k(N - 2 ^ k + 1),所以总的复杂度应该为O(N * logN * logN)。书上因为没有外边的k,所以通项公式为(N - 2 ^ k + 1),总复杂度为O(NlogN)。如果不是完全二叉树,结果可能会好一些。

在上面的解法中,每一条从根到叶的路径中的所有子路径都会被重新遍历一次,这是导致时间复杂度升高的原因。如果可以在遍历一条最长的路径中,也同时计算子路径是否满足所求,就可以降低复杂度,因此可以借鉴“在数组中计算所有累加和为指定值的子数组数量”的解法。

在遍历一条从根到叶的路径时,不断计算从根到当前的累加和,并查找之前的累加和中是否存在part - 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:
    int pathSum(TreeNode* root, int sum) {
        hashSum.insert(pair<int, int>(0, 1));
        pathCnt(root, sum);
        return cnt;
    }
private:
    int cnt = 0, part = 0;
    unordered_map<int, int> hashSum;
    void pathCnt(TreeNode* root, const int sum)
    {
        if(root == nullptr) return;
        part += root->val;
        unordered_map<int, int>::iterator iter;
        if((iter = hashSum.find(part - sum)) != hashSum.end()){
            cnt += iter->second;
        }
        hashSum[part]++;
        pathCnt(root->left, sum);
        pathCnt(root->right, sum);
        hashSum[part]--;
        if(hashSum[part] == 0) hashSum.erase(part);
        part -= root->val;
    }
};
发布了194 篇原创文章 · 获赞 2 · 访问量 7729

猜你喜欢

转载自blog.csdn.net/RayoNicks/article/details/105334465