前端算法必刷题系列[68]

286 阅读3分钟

这是我参与更文挑战的第 21 天,活动详情查看 更文挑战

这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。

130. 最小栈 (min-stack)

标签

  • Stack
  • 简单

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

设计一个支持 push ,pop ,top 操作,并能在常数时间检索到最小元素的栈

push(x) —— 将元素 x 推入栈中。 pop() —— 删除栈顶的元素。 top() —— 获取栈顶元素。 getMin() —— 检索栈中的最小元素

pop、top 和 getMin 操作总是在 非空栈 上调用。

示例 1

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

基本思路

首先注意我们需要常量级时间复杂度内找到最小值,那么肯定不能临时排序的。

我们想到用一个辅助栈minStack,用于存放主栈不同时期的最小值。第一个元素直接入栈,之后入栈的元素,会和 minStack 的栈顶元素比较,如果更小,则入 minStack 栈,minStack 栈顶始终是主栈的最小值

每当有元素出栈时,要判断出栈的是否是最小元素,如果是,则 minStack 的栈顶也出栈。

写法实现

var MinStack = function() {
    this.stack = []
    this.minStack = []
};

/** 
 * @param {number} val
 * @return {void}
 */
MinStack.prototype.push = function(val) {
    this.stack.push(val)
    if (this.minStack.length === 0 || val <= this.getMin()) {
        this.minStack.push(val)
    }
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
    // 判断出栈的是否是最小元素,是的话就把最小栈顶推出
    if (this.getMin() === this.stack.pop()) {
        this.minStack.pop();
    }
};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
    return this.stack[this.stack.length - 1]
};

/**
 * @return {number}
 */
MinStack.prototype.getMin = function() {
    // 取最小栈的栈顶元素,就是最小的
    return this.minStack[this.minStack.length - 1];
};

131. 二叉树中的最大路径和 (binary-tree-maximum-path-sum)

标签

  • 二叉树
  • 困难

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径至少包含一个节点,且不一定经过根节点

路径和是路径中各节点值的总和

给你一个二叉树的根节点 root ,返回其 最大路径和

示例 1:

image.png

输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

示例 2:

image.png

输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

基本思路

这题我们关键要注意这几点即可

  • 递归的核心就是找最小子问题,本题的核心就是考虑实现一个简化的函数 maxGain(node),该函数计算二叉树中的一个节点的最大贡献值,具体而言,就是在以该节点为根节点的子树中寻找以该节点为起点的一条路径,使得该路径上的节点值之和最大

  • 思考递归问题,不要纠结细节实现屏蔽细节地思考。递归就两要素,1. 调用自身,2. 递归出口

  • 结点有可能是负值,递归发现左右节点贡献为负,需要舍弃,直接为 0,就是不往下走。

本题虽然是困难,但实际不难,直接看看注释代码应该能清楚地理解,如果不理解请下面评论区留言。

写法实现

var maxPathSum = function(root) {
    let maxSum = Number.MIN_SAFE_INTEGER;

    // 求最大路径的函数
    const maxGain = (node) => {
        // 递归到 null 直接返回 0,路径不增加
        if (node === null) {
            return 0
        }
        // 递归计算左右子节点的最大贡献值,
        // 注意要大于 0 时再累计,否则直接为 0,因为节点值可能是负的

        let leftGain = Math.max(maxGain(node.left), 0);
        let rightGain = Math.max(maxGain(node.right), 0);

        // 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
        let newpath = leftGain + node.val + rightGain;

        // 跟历史最大比较
        maxSum = Math.max(maxSum, newpath);

        // 返回节点的最大路径
        return node.val + Math.max(leftGain, rightGain);
    }

    maxGain(root);
    return maxSum;
};

另外向大家着重推荐下这个系列的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 点击此处交个朋友 Or 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

参考