2021.10.18 力扣- 路径总和 III

这篇博客探讨了一道经典的二叉树问题,即寻找节点值之和等于目标值的路径数量。博主首先介绍了简单的深度优先搜索(DFS)暴力解法,指出了代码中可能导致重复计数的问题。接着,博主提出了一种使用前缀和和哈希表优化的解决方案,通过记录每个节点到根节点的路径和,避免了重复计算。在优化过程中,博主也详细解释了代码中需要注意的细节,如添加和删除前缀和的时机。
摘要由CSDN通过智能技术生成

题目描述:

给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。

路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

示例 1:

 方法一:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
 class Solution {
 public:
     int ans = 0;
     //vector<vector<int>> ans2;
     //void dfs(TreeNode* cur, int targetSum, int states, vector<int> states2)
     void dfs(TreeNode* cur, int targetSum, int states)
     { 
         if (cur == nullptr) return;
         states += cur->val;
         //states2.push_back(cur->val);
         if (states == targetSum)
         {
             ans++;
             //ans2.push_back(states2);
         }
         //dfs(cur->left, targetSum, states, states2);
         dfs(cur->left, targetSum, states);
         //dfs(cur->right, targetSum, states, states2);
         dfs(cur->right, targetSum, states);
         states -= cur->val;
         //states2.pop_back();
     }
     void recur(TreeNode* cur,int targetSum)
     {
         if (cur == nullptr) return;
         vector<int> states2 = {};
         //dfs(cur, targetSum, 0, states2);
         dfs(cur, targetSum, 0);
         recur(cur->left, targetSum);
         recur(cur->right, targetSum);
     }
     int pathSum(TreeNode* root, int targetSum) {
         recur(root, targetSum);
         //for (int i = 0; i < ans2.size(); i++)
         //{
         //    for (int j = 0; j < ans2[i].size(); j++)
         //    {
         //        cout << ans2[i][j] << " ";
         //    }cout << endl;
         //}
         return ans;
     }
 };

经典题目,就这样简单的暴力解法却总是做不出来,今天拿出来解决了吧。代码中的注释部分为存储每一条符合的路径。

在以下段中,我习惯性的把if语句放在了states += cur->val 之前,但是这样会导致在后续遍历cur的左右子树时,会将同一条路径重复判断两次。

         states += cur->val;
         //states2.push_back(cur->val);
         if (states == targetSum)
         {
             ans++;
             //ans2.push_back(states2);
         }

方法二:

 class Solution {
 public:
     int ans = 0;
     void recur(TreeNode* cur, int targetSum,int curpresum, unordered_map<int, int>& mappresum)
     {
         if (cur == nullptr) return;
         curpresum += cur->val;
         if (mappresum.count(curpresum - targetSum))
         {
             ans += mappresum[curpresum - targetSum];
         }
         mappresum[curpresum]++;
         recur(cur->left, targetSum, curpresum, mappresum);
         recur(cur->right, targetSum, curpresum, mappresum);
         mappresum[curpresum]--;
         curpresum -= cur->val;
     }
     int pathSum(TreeNode* root, int targetSum) {
         unordered_map<int, int> mappresum;
         mappresum[0]++;
         int curpresum = 0;
         recur(root, targetSum, curpresum, mappresum);
         return ans;
     }
 };

 使用前缀和,每次遍历时,记录下从根节点到该节点cur的前缀和curpresum,然后在哈希表中查找是否存在某个节点的前缀和为curpresum - targetsum,如果有说明这个节点到cur的路径之和就是targetsum。

由于可能存在某条路径的起始位置是根节点,导致curpresume == targetsum,所以在递归之前就要往哈希表中添加0这个数字。

注意我在写的过程中有个问题,在下方的代码中,我原先将 mappresum[curpresum]++; 放在了if语句之前,但这样会导致先往哈希表中添加了curpresum这个数字,如果targetSum是0的话,就会错误多计算一条路径。

另外,我一开始将 ans += mappresum[curpresum - targetSum]; 写成了ans++,但是满足前缀和为curpresum - targetSum的可能有多种情况。

         curpresum += cur->val;
         if (mappresum.count(curpresum - targetSum))
         {
             ans += mappresum[curpresum - targetSum];
         }
         mappresum[curpresum]++;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值