Skip to content

ARTS 第三十二周(2019.11.04~2019.11.10) #32

@catcuts

Description

@catcuts

ARTS 第三十二周(2019.11.04~2019.11.10)

Algorithm 二叉树的锯齿形层次遍历(中等难度)

题目

二叉树的锯齿形层次遍历(中等难度)

代码

/**
 * Definition for a binary tree root.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var zigzagLevelOrder = function(root, receiver, level = 1, rightToLeft = true) {
    // 若为空树则直接返回空数组
    if (!root) return receiver || [];
    // 否则先初始化
    receiver = receiver || [[root.val]];
    // 然后取出左右节点,并计算出下一层的层序
    // 这个层序对应数组的下标,该层的所有节点数值都会被放入该下标对应的元素数组中
    // 从而生成最终结果
    let { left, right } = root, nextLevel = level + 1;
    // 若有左节点
    if (left) {
        // 则先将左节点的值放入对应数组
        if (receiver[level]) {
            // 如果是从右往左则放在数组首位
            if (rightToLeft) receiver[level].unshift(left.val);
            // 否则放在数组末尾
            else receiver[level].push(left.val);
        }
        else receiver[level] = [left.val];
        zigzagLevelOrder(left, receiver, nextLevel, !rightToLeft);
    }
    // 若有右节点,同理
    if (right) {
        if (receiver[level]) {
            if (rightToLeft) receiver[level].unshift(right.val);
            else receiver[level].push(right.val);
        }
        else receiver[level] = [right.val];
        zigzagLevelOrder(right, receiver, nextLevel, !rightToLeft);
    }
    // 最终返回结果
    return receiver;
};

执行结果:通过
执行用时:60 ms,在所有 javascript 提交中击败了 93.15% 的用户
内存消耗:34.1 MB,在所有 javascript 提交中击败了 26.56% 的用户

思路:
若为空树则直接返回空数组,否则先初始化
然后取出左右节点,并计算出下一层的层序
这个层序对应数组的下标,该层的所有节点数值都会被放入该下标对应的元素数组中
从而生成最终结果
其中,若有左节点,则先将左节点的值放入对应数组
再递归调用处理该左节点,将其子子孙孙层节点的值放入对应数组中
放入数组时,如果是从右往左则放在数组首位,否则放在数组末尾
若有右节点,同理
最终返回结果

对比:
与高分对比:
本代码运行 33 个测试用例花费约 60ms,平均一个测试用例约 1.82ms;
高分代码运行 33 个测试用例花费约 60ms,平均一个测试用例约 1.82ms。
思路相似代码略。

Review 使用看门狗来确保 Node.js 程序的健康状况

阅读:
Ensuring healthy Node.js program using watchdog timer

点评:
在 Node.js 程序中往往充满异步操作,有些异步操作是发送 http 请求,有些异步操作是访问数据库。

在这些异步操作中,都需要与一个远程或本地的进程进行连接,并从这个连接上获得响应。

当响应迟迟无法获得时,使用 async-await 的程序就会阻塞,从而使下一个任务无法执行。

此时一种可行的方法是重启该程序。

这种方法的一种实现是使用定时器对连接进行超时监控,也就是看门狗,
一旦任务执行超过预设时间,则退出程序,由程序外部的监控进程(如 pm2)来重启它。

一种简单的实现是使用 setTimeout,但是正如文中代码所示,
如果任务中包含同步阻塞任务,则 setTimeout 也会被阻塞,从而无法达到超时监控效果

所以可以考虑使用 setTimeout + Kubernetes + [lightship](https://github.com/gajus/lightship) 来达到进程外超时监控。

扩展阅读:

Tip 异步回调里抛出的错误

异步回调里抛出的错误,只有异步回调内部才能捕捉到,外部是捕捉不到的。
比如:(详见注释)

(async function test () {
    try {
        await new Promise((resolve, reject) => {
            try {
                setTimeout(() => {
                    // 这里是 setTimeout 回调里抛出的错误
                    // setTimeout 外部的 try-catch 是捕捉不到的
                    // 注释掉此句,使用 reject 即在 reject 所在 promise 外部用 .catch 或 try-catch 捕捉到
                    throw new Error();  
                    // 如果使用 reject
                    // 只有 reject 所在的 promise 外部才能捕捉到该 reject
                    reject(new Error());
                    console.log('after rejected');
                }, 1000);
            } catch(e) {
                console.log(`捕捉 setTimeout 回调内部的错误:${e}`);
            }
        }).catch(e => {
            console.log(`用 .catch 捕捉 promise 内部的错误:${e}`);
        });
    } catch(e) {
        // 已经被 .catch 捕捉到,所以错误未触及此处
        console.log(`用 try-catch 捕捉 promise 内部的错误:${e}`);
    }
})();

Share [知乎文章] 如何写好业务代码?

分享一篇知乎文章
如何写好业务代码?

本文分享了在面对复杂业务时如何编写出好的业务代码的方法论,
并且用实际业务场景作为示例,一步步推导出这套方法论。

首先面对复杂的业务流程,最直接的方法就是“过程分解”。

过程分解的方式有很多,比如“流程引擎”,又比如“依赖数据库配置的流程处理”(有的数据库提供流程处理的配置)。

本文作者并不推荐数据库配置或流程引擎的方式来进行过程分解,因为它们带来的副作用太大。

作者认为,使用最朴素的“组合方法模式”,加以分解和抽象,就可以很好地对业务流程进行分解。

但是分解之后,虽然代码可读性和可维护性得到了提高,但是也带来了两个问题:

  • 领域知识被割裂肢解:简而言之就是样板代码太多,同一个问题的实现到处都是,缺少复用性
  • 代码业务表达能力缺失:因为只是进行过程分解,代码就不能显式地表达出它要实现的业务
    (可能因为 if-else 太多,破坏了业务表达的流畅性)

解决第一个问题的方法是“能力下沉”;而解决代码业务表达能力缺失的问题,可以通过引入“领域(对象)模型”来解决。

综上所述,作者提出的写好复杂业务代码的方法论就是“即自上而下的结构化分解 + 自下而上的面向对象分析”。

其实看的一知半解,这里只是做一个很不严谨的作者观点提炼,便于以后实践参考。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions