Arts 第二十二周(8/12 ~ 8/18)

ARTS是什么?
Algorithm:每周至少做一个leetcode的算法题;
Review:阅读并点评至少一篇英文技术文章;
Tip:学习至少一个技术技巧;
Share:分享一篇有观点和思考的技术文章。

Algorithm

LeetCode 124. Binary Tree Maximum Path Sum

题目解析

二叉树问题,题目要求出一个二叉树的最大路径和,路径和就是把一条路径上面节点的值加起来,这一题的难点在于路径的方向不固定,只要是任意两点间的通路都算是有效路径,如果不提前列出合理的规划,这道题将无从下手。一般来说,解决树的问题都需要用到递归,树上的搜索,本质上也是深度优先搜索,但是这里会有两种考虑方式,一个是自底向上的分治,也就是进入递归,一开始不做任何节点上面的计算或者是处理,直接进入到下一层递归,直到到了最底层,然后再开始计算并返回答案,然后上层树节点的递归函数就会收到下层返回的结果,这样做的好处是,一个节点可以获知其子树的局部答案;另外一个是自顶向下的遍历搜索,这个和之前的思路完全相反,也就是先处理当前节点的内容,处理完后去到下一层节点,这种方法一般没有返回值,但是一般会有一个全局或者是引用变量,用来记录遍历过程中的内容。

我们再回过头来看这道题,在递归遍历的过程中,对于当前节点,其在路径中可以是路径尾,路径头(假设路径是从上到下的,其实在这道题中,没有头尾的概念),也可以是路径中的一个节点。那怎么判断呢?这时我们得需要当前节点左右子树的信息,所以我们可以考虑使用之前提到的 自底向上 的分治,有了当前节点,左右子树到当前节点的最大路径,我们可以看看这里会有几种情况,我用 root 表示当前节点,left 表示左子树到 root 的最大和的路径,right 表示右子树到 root 的最大和的路径:

  • root 和左右路径形成路径(left - root - right)
  • root 和左路径形成路径(left - root)
  • root 和右路径形成路径(root - right)
  • root 自成路径(root)

你可以看到这四种情况都会把当前节点考虑在内,我们可以更新这里的最大值。但是需要注意的是,我们返回的时候,第一种情况是不能返回的,因为对于上一层节点来说,其无法形成有效的路径,因此我们只需要将 2,3,4 中的最大值返回即可,当然,更新全局答案的时候,这 4 种情况都需要考虑在内的。


参考代码

private int maximum = Integer.MIN_VALUE;

public int maxPathSum(TreeNode root) {
    if (root == null) {
        return 0;
    }
    
    helper(root);
    
    return maximum;
}

private int helper(TreeNode root) {
    if (root == null) {
        return 0;
    }
    // 如果左右子树返回的最大路径值小于 0
    // 直接将值设为 0,也就是不考虑对应的路径
    int leftMax = Math.max(0, helper(root.left));
    int rightMax = Math.max(0, helper(root.right));
    
    maximum = Math.max(root.val + leftMax + rightMax, maximum);
    
    return Math.max(leftMax + root.val, rightMax + root.val);
}
复制代码

Review

HTTP caching

一篇介绍 HTTP 缓存的文章

缓存可以减少客户端发送到服务器端的请求的数量,来达到减少服务器端压力的目的,而且缓存也会有很多种,文章这里主要讲了两种缓存,一种是 公有缓存,另外一种是 私有缓存,公有缓存类似于代理服务器,其面向的是多个用户,而私有缓存则相反,其仅仅面向一个用户,比如浏览器中的缓存就是私有缓存。

缓存一般只对 Get 方法起作用,想想应该不难发现,其他的方法比如 Post、Delete 是需要改动服务器上面的数据的,因此服务器端必须知道。

HTTP 中的 Cache-Control 头字段用来表明缓存指令:

  • 不要缓存客户端的请求或者服务器端的响应
    Cache-Control: no-store
    复制代码
  • 使用缓存之前,需要发送客户端请求到服务器端去验证
    Cache-Control: no-cache
    复制代码
  • 如果一个请求或者响应是 public 的,说明对于任何设备,都可以保存这个响应或者请求,不管这个用户是谁;如果一个请求或者响应是 private 的,那么只有该用户的私有缓存,比如浏览器才能缓存该信息
    Cache-Control: public
    Cache-Control: private
    复制代码
  • 设置缓存的新鲜度,也就是表明这个缓存的一个保质期
    Cache-Control: max-age=<seconds>
    复制代码
  • 可以添加 must-revalidate,表明必须使用没有过期的缓存
    Cache-Control: must-revalidate
    复制代码

在 HTTP/1.0 中,可以考虑使用 Pragma 替代 Cache-Control 当发生 Cache-Control 缺失的情况

因为服务器上面的资源和数据往往是在不断变化的,因此缓存有时候并不能很好的表现当前的数据情况。一个缓存往往会有一个过期时间,过了这个时间,缓存就会被认为是 “过期的”,过期时间可以按照下面的公式计算:

expirationTime = responseTime + freshnessLifetime - currentAge
复制代码

其中 responseTime 收到响应或者请求,缓存信息的时间,freshnessLifetime 是类似 “max-age” 的值,currentAge 表示当前的剩下的新鲜度。

这里会有一个问题就是,缓存的内容之间也会存在依赖关系,比如 CSS,JS,还有 HTML 文件,三者相互依赖,如果这时仅仅更改其中一个文件的缓存内容,会导致其他的所有文件都出问题,所以这时会对缓存的文件添加一个 hash 或者版本号,如果改变,新的文件会被缓存,但是旧的文件会依然存在一段时间,可以参照下图:

另外缓存的内容可能会有格式上面的区分,比如同一个内容,有可能是给手机端用的,也有可能是给 web 端用的,我们可以使用 Vary: User-Agent 字段去让缓存端发送缓存的时候考虑 Accept-Encoding 中的标明的格式是不是和缓存的内容一致。


Tip

  1. 当用户在浏览器导航栏输入信息的时候,浏览器内部发生的变化:

    • 用户输入
      • 地址栏会判断输入的内容是 请求 URL 还是 搜索内容,浏览器加载地址后,标签页上的图标就会变成加载状态
    • URL 请求过程
      • 浏览器进程会通过 进程间通信(IPC)的方式把 URL 发送给网络进程,网络进程会执行上一节讲的 HTTP 请求流程
      • Content-Type 在这里是一个非常重要的字段,浏览器会去根据这个字段去判断是要将内容交给 下载管理器 还是通知 渲染进程
    • 准备渲染进程
      • 通常来说每打开一个标签,浏览器就会重新分配一个渲染进程。但是如果从 A 页面打开 B 页面,且 A,B 属于同一站点的话(同 IP 同端口),那么 B 页面复用 A 页面的渲染进程
    • 提交文档
      • 提交文档” 是由浏览器进程发出的,当渲染进程收到 “提交文档” 消息后,会和网路进程建立数据传输的 “管道
      • 当文档数据传输完成后,渲染进程会返回 “确认提交” 到浏览器进程
      • 浏览器收到 “确认提交” 后,会更新页面状态,包括安全栏、地址栏的 URL、前进后退的历史状态、并更新 web 页面
      • 到这里,一个完整的导航流程就走完了,接下来回到渲染阶段
    • 渲染阶段
      • 一旦页面生成完成,浏览器会发一个消息给浏览器进程,浏览器会停止标签图标上面的加载动画
  2. 了解了 TCP 的 3 次握手,之前不理解为什么是 3 次。可以把 client-server 模型中的 client 和 server 想象成两个人,这两个人不知道对方是聋是哑,第一次握手,由 client 发送信息,server 这边收到了,知道 client 可以发送信息,不是哑巴,但是这个时候,server 并不知道 client 能不能接收信息,client 这边对 server 的情况也一无所知,于是,第二次握手,基于之前的信息,server 这边会回复 client,client 这边收到了 server 的信息,表明 server 接收到了之前的消息并回复了,也说明 server 不聋不哑,但是这时 server 端还是不知道 client 能否接收信息,第三次握手,client 基于收到的信息回复 server,server 收到后,知道 client 不聋不哑,于是在这个时候连接建立。你可能会问,为什么要搞这么复杂,直接开始对话不就好了,现实生活中我们也是这样做的啊。其实 3 次是 “在不可靠的信道上传输信息” 这一需求的最小次数,信息在信道上的传递并不像我们人和人之间面对面讲话这么简单,client-server 之间可能还会有成百上千个机器,比如说路由、CDN、正向代理、反向代理,这中间任何一个环节出问题都会导致信息的丢失,以及无谓的等待,因此正确的建立连接事关重要,TCP 3 次握手正是为了建立正确的连接,这里的 3 次也是理论上的最小次数。


Share

这周刷 LeetCode 上面二叉树问题的一些总结和思考

LeetCode 二叉树问题总结

转载于:https://juejin.im/post/5d55a093f265da03934bda3b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值