当前位置: 首页 > news >正文

Leetcode 437 -- dfs | 前缀和

题目描述

路径总和

思路

由于题目的范围较小,所有点的个数小于一千,因此我们可以暴力 d f s dfs dfs 套$ dfs$,以每一个节点作为根节点,然后向下遍历求每一个节点到该节点的路径和,时间复杂度为 O ( N 2 ) O(N^2) O(N2)
但这种做法肯定会有大量重复计算,那么有没有什么办法可以消除这些重复计算呢?

我们想一下,在暴力 d f s dfs dfs 套$ dfs$中,我们的每个节点都会计算出每一个下层节点到该节点的路径和,那么当我们遍历到下层节点的时候,有没有什么办法可以利用这些上层节点已经计算完的数据呢?
例如下图:

                     1
                    / 
                   2    
                  / 
                 3   
                / 
               4  

当我们遍历到节点 4 4 4 的时候,我们是可以得到节点 1 1 1 到节点 2 , 3 , 4 2,3,4 2,3,4 和节点 2 2 2 到节点 3 , 4 3, 4 3,4 以及节点 3 3 3 到节点 4 4 4 的路径之和的,问题是该怎么利用?
想要利用这些数据,我们就不能再从根节点往下找路径和,为什么?
如果我们从根节点往下找路径和,那么上层节点是什么样与我们根本就没有关系,我们只关心下层节点是什么样子的。
因此,我们需要转换思路,求每个根节点到它上层所有节点的路径之和,这样,我们就可以利用这些上层节点已经计算完的数据了。

问题来了,该怎么利用?
在思考这个问题之前,你应该发现,这些数据其实就是以每一个节点作为根节点求得的到其下层节点的前缀和
因此我们只需要将这些信息用一个数据结构保存起来即可!
现在,走到节点 4 4 4 的时候,路径和为 1 + 2 + 3 + 4 = 10 1+2+3+4=10 1+2+3+4=10,此时如果存在路径和等于 t a r g e t S u m − 10 targetSum-10 targetSum10,那么就存在节点 4 4 4 到上层某个节点的一条符合要求的路径和。
并且这条路径肯定是和节点 4 4 4 联通的,因为我们去掉的是由根节点 1 1 1 到某个节点 x x x 的路径,得到的是节点 x x x 到节点 4 4 4 的路径。

所以说,我们前缀和的定义为:根节点到每个下层节点的前缀和。
注意这个根节点是最顶层的根节点,而不是将每一个节点都视为根节点,因为我们只需要知道最顶层的根节点到每一个节点的前缀和就可以找到某一个节点到任意上层节点的前缀和,通过减法。
另外,我们还需要记录某一个前缀和的个数,因为节点的值可能为 0 0 0
另外一些细节见代码。

代码–前缀和

/**
 * 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:
    unordered_map<long long, int> prefix;   // <前缀和, 个数>
    int dfs(TreeNode *root, long long curSum, int targetSum)
    {
        if(root == NULL)    return 0;

        int ans = 0;
        curSum += root->val;
        if(prefix.count(curSum - targetSum))    // 不存在时不会创建对象
            ans = prefix[curSum - targetSum]; // 上层是否存在前缀和[curSum-trgetSum]
        // 题目规定,路径和之能往下走,所以说我们需要回溯 prefix 的值,否则就会出现往上走的情况
        prefix[curSum] ++ ;
        ans += dfs(root->left, curSum, targetSum);
        ans += dfs(root->right, curSum, targetSum);
        prefix[curSum] -- ;

        return ans;
    }
    int pathSum(TreeNode* root, int targetSum) {
        if(root == NULL)    return 0;
        prefix[0] = 1;      // 初始化前缀和
        return dfs(root, 0, targetSum);
    }
};
http://www.dtcms.com/a/112537.html

相关文章:

  • 大数据概念介绍
  • 高可用完全分布式集群启动命令
  • 基于 Java 的异步任务管理器的设计与实现方案
  • Currying柯里化
  • 【教程】Windows下 Xshell 连接跳板机和开发机
  • 基于PI控制和卡尔曼滤波的光通信相位偏差估计和补偿算法matlab仿真
  • 前端快速入门学习1——使用工具
  • [ISP 3A ] AE的常用算法分析
  • chown和chmod的区别
  • 使用内存数据库来为mapper层的接口编写单元测试
  • AI大模型时代前后端技术演进:MCP神经中枢架构下的技术栈抉择
  • Java项目之基于ssm的教务信息平台的设计与实现
  • 算法思想之双指针(一)
  • 深度学习处理文本(11)
  • Prolog语言的移动UI设计
  • COBOL语言的数据库交互
  • Pascal语言的设备管理
  • 【含文档+PPT+源码】基于SpringBoot+vue的疫苗接种系统的设计与实现
  • Scala学习总结③
  • JavaScript事件循环深度解析:从一道面试题看微任务与宏任务调度机制
  • 详细说明Qt 中共享内存方法: QSharedMemory 对象
  • 59.基于ssm和vue学生考试成绩管理系统
  • HTML快速上手
  • 如何在 GitHub 上开源一个小项目:从创建到长期维护的完整指南
  • 关键业务数据如何保持一致?主数据管理的最佳实践!
  • 出现次数超过一半的数(信息学奥赛一本通-1186)
  • 已经使用中的clickhouse更改数据目录
  • Haskell语言的区块链扩展性
  • 3.4/Q2,Charls最新文章解读
  • 抓Edge兼容模式中IE浏览器中的包--渗透测试环境配置