1

引言

时间过得好快,已经到了第四周学习打卡环节,也是本次活动的最后一周。认识三掌柜的想必都知道,我持续创作技术博客已经有6年时间了,固定每个月发布不少于6篇博文。同时,自己作为一名热爱分享的开发者,像ARTS这样的活动自然少不了我。由于我是打算挤在一起分享,之前都是做了本地文档记录,所以直接把内容整合起来即可,那么接下来就开启我的第四周打卡咯。

Algorithm

本周我想分享一个比较经典的算法问题,该算法题也是力扣(Leetcode-449 https://leetcode.cn/problems/serialize-and-deserialize-bst/de...)的经典算法题目:序列化和反序列化二叉搜索树问题。
序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。
设计一个算法来序列化和反序列化 二叉搜索树 。 对序列化/反序列化算法的工作方式没有限制。 您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。
编码的字符串应尽可能紧凑。
思路: 给定一棵二叉树的「先序遍历」和「中序遍历」可以恢复这颗二叉树。给定一棵二叉树的「后序遍历」和「中序遍历」也可以恢复这颗二叉树。而对于二叉搜索树,给定「先序遍历」或者「后序遍历」,对其经过排序即可得到「中序遍历」。因此,仅对二叉搜索树做「先序遍历」或者「后序遍历」,即可达到序列化和反序列化的要求。此题解采用「后序遍历」的方法。
序列化时,只需要对二叉搜索树进行后序遍历,再将数组编码成字符串即可。
反序列化时,需要先将字符串解码成后序遍历的数组。在将后序遍历的数组恢复成二叉搜索树时,不需要先排序得到中序遍历的数组再根据中序和后序遍历的数组来恢复二叉树,而可以根据有序性直接由后序遍历的数组恢复二叉搜索树。后序遍历得到的数组中,根结点的值位于数组末尾,左子树的节点均小于根节点的值,右子树的节点均大于根节点的值,可以根据这些性质设计递归函数恢复二叉搜索树。
具体的JS实现代码如下所示:

var serialize = function(root) {
    const list = [];

    const postOrder = (root, list) => {
        if (!root) {
            return;
        }
        postOrder(root.left, list);
        postOrder(root.right, list);
        list.push(root.val);
    }

    postOrder(root, list);
    const str = list.join(',');
    return str;
};

var deserialize = function(data) {
    if (data.length === 0) {
        return null;
    }
    let arr = data.split(',');
    const length = arr.length;
    const stack = [];
    for (let i = 0; i < length; i++) {
        stack.push(parseInt(arr[i]));
    }

    const construct = (lower, upper, stack) => {
        if (stack.length === 0 || stack[stack.length - 1] < lower || stack[stack.length - 1] > upper) {
            return null;
        }
        const val = stack.pop();
        const root = new TreeNode(val);
        root.right = construct(val, upper, stack);
        root.left = construct(lower, val, stack);
        return root;
    }

    return construct(-Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, stack);
};

复杂度分析:
时间复杂度:O(n)O(n)O(n),其中 nnn 是树的节点数。serialize\textit{serialize}serialize 需要 O(n)O(n)O(n) 时间遍历每个点。deserialize\textit{deserialize}deserialize 需要 O(n)O(n)O(n) 时间恢复每个点。
空间复杂度:O(n)O(n)O(n),其中 nnn 是树的节点数。serialize\textit{serialize}serialize 需要 O(n)O(n)O(n) 空间用数组保存每个点的值,递归的深度最深也为 O(n)O(n)O(n)。deserialize\textit{deserialize}deserialize 需要 O(n)O(n)O(n) 空间用数组保存每个点的值,递归的深度最深也为 O(n)O(n)O(n)。

Review

本周分享一个自己在学习区块链的英文文章,文章是关于比特币的实际运作方式,文章链接https://michaelnielsen.org/ddi/how-the-bitcoin-protocol-actua... ,这篇文章从这里开始就进入更多的技术视角,了解比特币的一些技术细节,但仍然是在整体上了解比特币协议框架,熟悉以比特币为代表的区块链项目的技术范式。
下面摘抄部分内容做分享:

A problem with the first version of Infocoin is that Alice could keep sending Bob the same signed message over and over. Suppose Bob receives ten copies of the signed message “I, Alice, am giving Bob one infocoin”. Does that mean Alice sent Bob ten different infocoins? Was her message accidentally duplicated? Perhaps she was trying to trick Bob into believing that she had given him ten different infocoins, when the message only proves to the world that she intends to transfer one infocoin.
What we’d like is a way of making infocoins unique. They need a label or serial number. Alice would sign the message “I, Alice, am giving Bob one infocoin, with serial number 8740348”. Then, later, Alice could sign the message “I, Alice, am giving Bob one infocoin, with serial number 8770431”, and Bob (and everyone else) would know that a different infocoin was being transferred.

Infocoin的第一个版本的一个问题是,Alice可能会不断地向Bob发送相同的签名消息。假设Bob收到十份签名信息“我,Alice,给Bob一个信息币”。这是不是意味着爱丽丝给鲍勃发了十个不同的信息币?她的信息是不是被意外复制了?也许她是想欺骗鲍勃,让他相信她给了他十个不同的信息币,而这条信息只向世界证明了她打算转移一个信息币。
我们想要的是一种使信息币独一无二的方式。他们需要一个标签或序列号。爱丽丝会在信息上签名:“我,爱丽丝,给鲍勃一个序列号为8740348的信息币”。然后,爱丽丝可以在消息上签名“我,爱丽丝,给鲍勃一个序列号为8770431的信息币”,鲍勃(和其他人)就会知道另一个信息币正在被转移。

Technique/Tips

这次分享一个关于前端开发中的重要知识点,在前端开发过程中涉及到算法相关的知识,贪心算法的相关知识点使用。这里以买卖股票的最佳时机的前端开发中的实用场景进行分享,这不是一个算法题哦,这确确实实是在前端开发中能够用到的知识点,具体实现代码如下所示:

/**
 
* @param {number[]} p 价格
 
* @return {number} r 最优解
 
*/
 
var maxOptimal = function(p) {
 
    var r = 0;
 
    for(var i=1;i<=p.length;i++){
 
        if(p[i]>p[i-1]){
 
            r = p[i] - p[i-1] + r;
 
        }
 
    }
 
    return r;
 
};

Share

本次分享一下关于程序员是否需要考证的话题。对于这个话题,不同人有不同的看法,有人认为程序员只需要具备扎实的编程基础,丰富的项目经验和不断学习的态度,就可以胜任工作;而有些人则认为,程序员需要考取专业证书,这样才能证明自己拥有一定的专业技能和能力,也能够获得更好的工作机会和薪资待遇,提高自身的竞争优势。
在实际情况中,在大多数公司中,程序员的职业发展需要考虑到多方面的因素,如专业知识、技能水平、项目经验等。考证无疑是衡量一个程序员专业程度的一种方式,但并不是唯一的方式。如果一个程序员拥有丰富的项目经验、优秀的编程能力和对新技术的不断学习,也可以得到公司的认可和职业进阶的机会。
所以,个人认为程序员可以去考证,但是不是非必须的选择,一切还是以自身的实际情况决定的。

结束语

写到这里,第四周是游刃有余,已经完全适应了ARTS 打卡学习模式,总体来讲用一周的业余时间来分别研究这4件事情,总体来说每天花一些时间来分别研究这几件事情,然后一周的周末来一个总结,这样的方式也是相当不错的。截止到第四周,参与打卡的ARTS学习月就告一段落,但是自己不会跟着活动结束而结束,我会继续以这种方式来每周提升自己一点点,保持持续学习的状态,让自己在潜移默化中不断进步成长!


三掌柜
13.5k 声望5.9k 粉丝

一分耕耘,不一定有一分收获,但十分耕耘,一定会有一分收获!