ARTS(29)

1 Algorithm

二叉树遍历是通过某种特定的顺序对二叉树的节点有且仅访问一次,遍历能够将二叉树非线性结构转换为某种线性顺序。二叉树的遍历主要分为先序遍历中序遍历后序遍历三种,每一种都有递归和迭代两种方式实现。

二叉树节点定义如下

type TreeNode struct {
    Val int
    Left *TreeNode
    Right *TreeNode
}

1.1 递归遍历

二叉树是递归定义的,所以递归遍历二叉树就非常简单

// 先序遍历
func PreOrder(root *TreeNode, visite func(*TreeNode) ) {
    if root != nil {
        visited(root)
        PreOrder(root.Left, visited)
        PreOrder(root.Right, visited)
    }
}
// 中序遍历
func InOrder(root *TreeNode, visite func(*TreeNode)) {
    if root != nil {
        InOrder(root.Left, visited)
        visisted(root)
        Inorder(root.Right, visited)
    }
}
// 后续遍历
func PostOrder(root *TreeNode, visite func(*TreeNode)) {
    if root != nil {
        PostOrder(root.Left, visited)
        PostOrder(root.Right, visited)
        visisted(root)
    }
}

1.2 迭代遍历

递归调用实际上借助函数调用栈保存调用的信息,那么借助栈就可以迭代过程,同样达到递归效果。

1.2.1 先序迭代遍历

尾递归消除
上述先序递归是尾递归的形式,通过尾递归消除的方法就可以完成迭代遍历

func PreOrder(root *TreeNode, visite func (*TreeNode) ){
    stack := NewStack()
    stack.Push(root)
    for stack.Size() > 0 {
        node := stack.Pop()
        if node != nil {
            visite(node)
            stack.Push(node.Right)
            stack.Push(node.Left)
        }
    }
}

通用解法
上述尾递归消除迭代方法针对先序遍历可以很方便的实现,但是针对中序遍历和后序遍历并不通用,因此需要采用更加通用的方法

上图为先序遍历的抽象表示形式,对于每一个子树,一路遍历其左孩子,然后将其遇到右孩子逆序遍历。

func visitAlongLeftBranch(node *TreeNode, visit func(*TreeNode), stack *Stack) {
    for node != nil {
        visit(node)
        stack.Push(node.Right)
        node = node.Left
    }
}
func PreOrder(root *TreeNode, visit func(*TreeNode)) {
    stack := NewStack() 
    for {
        visitAlongLeftBranch(root, visit, stack)
        if stack.Size() == 0 {
            break
        }
        root = stack.Pop()
    }
}

1.3.2 迭代中序遍历

中序遍历的示意图如下

首先从跟节点一路向左孩子最深处,然后开始遍历没有最后一个左孩子的节点,然后进入右孩子的子树重复同样的操作,然后之前从根节点一路而下的节点逆序完成遍历

func goAlongLeftBranch(node *TreeNode, stack *Stack) {
    for node != nil {
        stack.Push(node)
        node = node.Left
    }
}
func InOrder(root *TreeNode, visit func(*TreeNode) ) {
    stack := NewStack()
    for {
        goAlongLeftBranch(root, stack)
        if stack.Size() == 0 {
            break
        }
        root := stack.Pop()
        visit(root)
        root = root.Right
    }
}

1.3.3 迭代后序遍历

迭代后序遍历的难度比较大,因为它不再属于尾递归,但是我们可以借助两个栈结构,来保存遍历的顺序

  1. 将根节点 Push 到第一个栈中;
  2. 循环下面的步骤直到第一个栈为空
    • 从第一个栈中 Pop 出节点,并 Push 到第二个栈中;
    • 将刚刚节点的左右两个节点分别 Push 到第一个栈中;
  3. 将第二个栈 Pop 并且遍历
func PostOrder(root *TreeNode, visit func(*TreeNode)) {
    first, second := NewStack(), NewStack()
    first.Push(root)
    for first.Size() > 0 {
        root = first.Pop()
        second.Push(root)
        if root.Left != nil {
            first.Push(root.Left)
        }
        if root.Right != nil {
            first.Push(root.Right)
        }
    }
    for second.Size() > 0 {
        visit(second.Pop())
    }
}

2 Review

10 years of professional blogging – what I’ve learned
从十年专业写作中学到的

2.1 建立个人标签

我要再一次重述一下我在 Twitter 上表述的我从十年专业写作中学到的内容,它是更大主题 湾区生活十年学到的 文章的后序。从专业角度来看,写作有巨大的影响力,我想持续地推荐给每一个人,尤其是那些生活在湾区的人,这样做的话可以给你志向、想法和兴趣带来不同的凡响。
听上去不错,但是行动起来却非常困难。当然每个人都知道建立博客的方法,但是困难的部分是如何找到自己的声音,找到其他人感兴趣的主题和建立长期的习惯。

2.2 心得

在讨论之前,下面是我一直以来形成的观点:

  • 标题是 80% 的工作,但是这是最后的工作。它必须是引人入胜的观点或者是非常重要的知识点;
  • 高质量的思考和观点都会有提高的空间,我们可以交流的的关于知识和人的 Venn 图仍然很小;
  • 思考一下写作作为你的职业生涯段,话很多的十年在写作上。那也就意味着不要仅仅是在 Quora 或者 Medium 上;
  • 比其他事情更专注于写作,并且制定计划。不要担心是否有读者,专注于内心;
  • 养成一个习惯,在日历上增加一个提醒项,每个周日抽出 2 个小时。让自己专注于空白文本框并且写下一些东西;
  • 我大部分写作都来自于我强烈同意和不同的言论和阅读,这些观点就会变成标题,然后成为文章;
  • 人们通常喜欢那些写下原创的想法,但是不是的。你仅仅是科技工业化的记者而已;
  • 邮件订阅者比 Twitter 或者 LinkedIn 甚至其他途径的粉丝值 100 倍,一个 Email 相当于真是的通道。
  • 当我开始在 VC 工作的时候,他们问到:为什么放弃想法?它是你的优势。讽刺的是他们在博客和 Twitter 上整天鼓励这些;
  • 一年一年额输出想法、知识点和观点是一种非常好的奉献方式,你就会弄清楚如何去抓住真正的价值。

接下来我们讨论其中的一些细节。

2.3 更详细的心得

标题是 80% 的工作,但是这是最后的工作。它必须是引人入胜的观点或者是非常重要的知识点。

标题通常被当成思考之前的模糊想法,但是事实上它是你做的最富有创造性的选择。标题是在每个推特上被标记为重要的内容,同样也是 Facebook 分享或者链接的标题,人们通常通过标题来找到这些内容。如果标题能够通过 裸测试 那么它就是最好的标题。那什么是 裸测试 呢?想象一下如果一段文字是如此引人入胜以至于即是它并不包含任何东西,人们也都会想要分享它。
最好的例子是我的作品是 增长的黑客是新的 VP 市场,刚开始在 twitter 上只有 20+ 的分享,然后它逐步变成一篇文章。为了通过 裸测试 ,也就意味着标题应当有自己的观点。如果这个太难了,通常的 好奇间隔 的模式的清单可以帮助到你。避免一些模糊的标题比如 我对 xxx 的看法,没有人会关心这个。所以在我的工作中,我通常写一个占位的标题开始写文章,在最后的时候,花大块的时间来迭代文章的标题直到它找到一个最好的。

高质量的思考和观点都会有提高的空间,我们可以交流的的关于知识和人的 Venn 图仍然很小。

你可能认为现在有很多关于科技、初创企业的博客,但是仍然提高的空间。你要想到 知识×交流×媒体 的空白。那么很有知识的人通常非常忙,尤其是那些被高度需求的知识。甚至如果将那些专家的脑袋戳开,让他们做除了工作以外的事情,但是通常不擅长沟通。制作专业的内容太困难了,通常都是非常是干涩、无聊、充满技术的,而这些是无法吸引观众的注意的。在这里我将媒体当做第三个属性,因为知识可以通过视频、长篇文章、播客或者演讲的方式来分享。当有一个专家写一篇很长的关于加密货币的文章,你也可以通常高度可视化的方式来完成改进。去找到那些空白处吧,并且深入其中。

写作是最可以扩展网络活动,只需要待在家里,而不用参加宴会或者会议,仅仅是将想法写下来。

当我刚刚搬到湾区的时候,我通常每周花费一个下午或者晚上在聚会、会议上。加上无数小时的时间在 1 对 1 交流上。这样一些年的努力工作,我差不多认识了 1000 多人,也只不过一面之缘。当我将同样的时间花在写作上,很快就解锁了 5000+ 人,而且每周的都可以往他们的邮箱里发送文章。
在会议上演讲是最浪费时间的,你花费了数个小数准备演讲,面向数百人讲述观点,和其中的少部分人维持着关系。被别人认出当然感觉非常棒,但是这个和写作还不能比较。我想在还能在十年前写的文章得到邮件反馈,这是非常不可思议的,但是这就是扩展的力量。

思考一下写作作为你的职业生涯段,话很多的十年在写作上。那也就意味着不要仅仅是在 Quora 或者 Medium

构建你的人际网络和你的观众,你的想法就是伴随你的职业生涯的东西。很大可能是这些能够持续几十年,它比出版的初创公司长的多,这也是我为什么拒绝在 Medium 或者 Quora 上发表的原因。我更喜欢那些允许自我发挥的开源软件,而且优先我的邮件列表并且定期备份。我以前在 Blogger 上写文章但是在被 Google 收购了他们就不在维护这个平台了。然后我转战 Typepad,但是又一次发现同样的事情发生了。

比其他事情更专注于写作,并且制定计划。不要担心是否有读者,专注于内心

开始发表你专业的想法和思考需要的能量非常高,因为刚开始没有人会阅读你的作品,但是关键是开始。你刚开始的主题和形式应该是你可以很轻松频繁地写下和维护的,获取刚开始每个月 500 字的写,无论你是否讨厌它,仅仅去行动就够了。找到你喜欢的,当你想要开始写下它们的时候,将有很多时间和它交互,也发现别人想要知道的东西。

养成一个习惯,在日历上增加一个提醒项,每个周日抽出 2 个小时。让自己专注于空白文本框并且写下一些东西。

几年时间的投入,写作任然非常困难。还有其他一些事情要做,比如需要腾出特定的时间来。我会关闭音乐,停止检查邮件,然后花几个小时写作来放空自己。虽然其中一部分变得容易了,但是核心的工作仍然是非常困难。因为在周日的晚上开始工作非常困难,这时候工作的邮件开始到达了。但是好的写作通常是在周日的晚上,每个月都会有好几次因为打扰而工作阻塞了。

我大部分写作都来自于我强烈同意和不同的言论和阅读,这些观点就会变成标题,然后成为文章

在一场活跃的午饭或者晚饭的讨论中,在这里撩人的观点被无意间提出:加密货币将会被广泛接受而且最终导致全球衰退。我通常会写下这些,如果它非常有趣并且被牢记,写下三四个支持论点的段落,然后将它转换为一篇文章。

人们通常喜欢那些写下原创的想法,但是不是的,你仅仅是科技工业化的记者而已。

把自己想象成一个记者,发现有趣的想法、产品或者你周边发生的一切有趣的事情,转换成更好更丰富的内容。这也就意味着你可以写基于被人想法的内容,而不是要让任何事情都是崭新的。就像初创公司的想法很少是崭新的,而且老的想法的组合,在科技行业的现象和想法也是同样的道理。

邮件订阅者比 Twitter 或者 LinkedIn 甚至其他途径的粉丝值 100 倍,一个 Email 相当于真实的通道。

对于一个专业的观众,邮件是唯一关注的KPI,没有比这个更加吸引人了。更重要的是,他们是独立分布式的,而且在十年之内都会跟随着你。但是这个并不是说其他订阅途径是不好的。考虑到我专注于搜集邮件的 UI 设计。主页和文章底部都是关注的重点,加上那些扰人的弹窗。

当我开始在 VC 工作的时候,他们问到:为什么放弃想法?它是你的优势。讽刺的是他们在博客和 Twitter 上整天鼓励这些。

VC 们花了好长时间才搞清楚如何宣传他们自己和他们的想法。

一年一年额输出想法、知识点和观点是一种非常好的奉献方式,你就会弄清楚如何去抓住真正的价值。

写作的第一年,我仅仅只有上百位观众,包括来自西雅图的朋友和同事,我的妹妹等等,不到一年我发现当我帮助初创公司募集资金的活动是巨大的资产。几年之后,直到你的公司被收购,一个超级棒的市场调查和副项目诞生了。

2. 4 创造是重要的-写作是一个子集

对我来说,写博客已经成为我构建人际关系和专业声誉的胜负手。它仅仅创造和输出内容的一种手段。你也可以通过其他手段来完成这项工作,比如视频、图片或者博客。或许你是一个开发者,你希望推广的你的开源项目。除了它能够工作,最重要的部分是开始分享你爹知识和观点。长此以往,就可以在这个平台上完成其他的工作。

2.5 额外的心得

还有,我想从我之前的文章中获得的心得来分享

  • 地毯式搜索关键领域并且坚持下来
  • 花时间找到你的自己的声音
  • 博客的形式和主题保持一致性
  • 慢慢来
  • 你擅长的主题要深入
  • 现实世界和虚拟世界要紧密联系
  • 拥抱全世界你的博客的读者
  • 通过头脑风暴来思考新的主题
  • 每一天观察统计
  • 过犹不及

3 Tips

Crontab 是 Linux 中定时执行任务的工具,这种方式比采用死循环的方式执行判断时间戳方便地多,而且不容易出错。

3.1 结构


每一个定时任务的执行如上图所示,一行记录代表一个执行任务,从左到右依次为:
[分钟] [小时] [每月的某一天] [每年的某一月] [每周的某一天]

3.2 如何添加任务

crontab -e 命令会进入默认的编辑器,然后编辑这个文件即可。

3.3 实例

  • 每天 02:00 执行任务
0 2 * * * /bin/sh backup.sh
  • 每天 5:00和17:00执行任务
0 5,17 * * * /scripts/script.sh
  • 每分钟执行一次任务

通常情况下,我们并没有每分钟都需要执行的脚本

 * * * * *  /scripts/script.sh
  • 每周日 17:00 执行任务
0 17 * * sun  /scripts/script.sh
  • 每 10min 执行一次任务
*/10 * * * * /scripts/monitor.sh
  • 在特定的某几个月执行任务
* * * jan,may,aug * /script/script.sh
  • 在特定的某几天执行任务
0 17 * * sun,fri /script/scripy.sh
  • 在某个月的第一个周日执行任务
0 2 * * sun  [ $(date +%d) -le 07 ] && /script/script.sh
  • 每四个小时执行一个任务
0 */4 * * * /scripts/script.sh
  • 每周一、周日执行任务
0 4,17 * * sun,mon /scripts/script.sh
  • 每个30秒执行一次任务

我们没有办法直接通过上诉类似的例子去执行,因为最小的是1min。但是我们可以通过如下的方法。

  * * * * * /scripts/script.sh
  * * * * *  sleep 30; /scripts/script.sh
  • 多个任务在一条命令中配置
 * * * * * /scripts/script.sh; /scripts/scrit2.sh
  • 每年执行一次任务
@yearly /scripts/script.sh

@yearly 类似于“0 0 1 1 *”。它会在每年的第一分钟内执行,通常我们可以用这个发送新年的问候。

  • 每月执行一次任务
@monthly /scripts/script.sh
  • 每周执行一次任务
@weekly /bin/script.sh
  • 每天执行一次任务
@daily /scripts/script.sh

每小时执行一次任务

@hourly /scripts/script.sh

系统重启时执行

@reboot /scripts/script.sh

4 Share

邮件是工作中最高效的沟通方式,在国外邮件文化十分盛行,尤其是在办公领域,而即时聊天消息(Instance message) 则是私人交流的方式。使用邮件沟通有以下的有点:

  • IM 的属性表明它往往是简短的消息交流,而这些消息往往没有经过认真的考虑,导致交流过程中噪声比较多;而邮件不一样,它需要你将思考的过程写下来,你需要在一封邮件中将要表达的事情全部描述清楚;
  • 邮件的回复功能可以将事情的全部处理流程展示清楚,能够做到可追踪和回溯,责任清晰;而 IM 则需要搜索你需要的了解的过往消息,大大增加查找有价值信息的难度;
  • IM 消息会打断你工作的流程,你需要不停地在工作环境和 IM 软件之间切换,这可能也是国内公司加班严重的原因,很多工作在 8 小时内完成;
  • 对于即时性很高的场景,有很多会议的应用可以帮助我们,比如 Zoom, Skype 等软件可以高效完成交流。
Comments
Write a Comment