zoukankan      html  css  js  c++  java
  • ARTS-WEEK-012

    Algorithm:

    117: Populating Next Right Pointers in Each Node II (Medium)

    填充二叉树的各个节点的下一同层节点。这道题有个 Follow up:You may only use constant extra space. 我在开始一直在想如何用常数空间解决,尝试像BFS一样的遍历顺序但用指针串起来,定义 last 和 current 节点,不停用 current 的左右子节点链接到last后面,并推进 current=current.next直到最后,最终每层右侧节点无法处理,进入死胡同。后来看到中文题目才明白 Follow up 是进阶要求而不是必须项,于是先用队列 BFS 实现出来,这时想到 BFS 中每一层可以用 length 约束控制本层边界,也可以用一个新队列只放这一层内容,而这正是链表法解这道题的思路,即遍历当前层链表,取所有 children 形成下一层的新链表,当前链表遍历至 next == null 说明该切换至下一链表,这需要保存和利用下一层的 head 节点。

        public Node connect(Node root) {
            if (root == null) return null;
            Node curr = root;
            Node head = null, level = null;
            // children
            while (curr != null) {
                // start new level list
                if (head == null) {
                    head = new Node();
                    level = head;
                }
                // add level
                if (curr.left != null) {
                    level.next = curr.left;
                    level = level.next;
                }
                if (curr.right != null) {
                    level.next = curr.right;
                    level = level.next;
                }
                curr = curr.next;
                if (curr == null) {
                    // next level
                    curr = head.next;
                    head = null;
                }
            }
            return root;
        }
    

    Review:

    Linkedin: How we reduced latency and cost-to-serve by merging two systems

    这篇文章介绍了一个在微服务架构中不常见的场景,合并服务。首先拆分服务更符合一般架构发展方向,使服务更加松耦合、隔离影响、更易扩展等,但是这也带了更多延迟、硬件资源消耗、服务成本和运营成本。文章通过一个具体案例结合一些记录数据,证明了他们减少了服务延迟并减少了大量成本(适合给老板看)。总结出拆分与合并是一个平衡过程,需要不断根据设计落地后运行效果重新评估。

    语言积累:Identity services, power many other applications, downstream services, cost-to-serve, operational overheads, re-evaluate some of our assumptions, incurred additional network hops, a right balance to strike in deconstructing systems, gradually ramped the change, decommission, annual savings

    Tip:

    Asynchonous vs Non-blocking

    异步与非阻塞,在不同语境和场景下定义不同,有时可以互换,有时却略有不同。

    1、在网络编程的IO模型中

    在经典的《UNIX Network Programming》第六章中,作者将IO模型分为 blocking IO、nonblocking IO、IO multiplexing (select, poll)、signal driven IO、asynchronous IO (aio) 五种模型。首先将所有IO操作分为1等待数据阶段和2从内核复制数据到用户进程阶段,前4种模型因为都需要在阶段2阻塞(blocking IO 和 IO multiplexing 在阶段1阻塞,nonblocking IO 和 signal driven IO 在阶段1不阻塞)。按照 POSIX 定义:同步IO操作会使请求进程阻塞直到IO操作完成,异步IO操作不会引起请求进程阻塞。因此前四种都是同步模型,只有最后一种 aio 模型在所有阶段都不阻塞,符合异步定义。

    其中值得注意的是 ,虽然 IO 多路复用模型(select、poll)在两个阶段都会阻塞,但它第一个 select 调用可以同时等待多个 IO 事件(这种循环称为 polling),这比单独 polling 一个 nonblocking IO 更加高效,在优化为 epoll 后更是处理海量连接的关键技术。

    2、在更通用的一般编程语境中

    首先阻塞和同步是一回事,即调用一个API,它阻塞当前线程直到返回结果回来。

    其次,非阻塞API指调用它时如果不能立刻返回结果,就返回错误而不进行等待,例如 tryLock() 这类函数,与此同时有别的办法进行更有效的等待,比如做其他事、过会重试或快速失败,一般不会 polling in a tight loop。

    最后,异步是指该API始终立刻返回,并在后台(其他线程)继续完成该请求,并通过一些其他方式拿到结果。

    3、在 OpenResty 等协程场景中

    在学习 OpenResty 的过程中,情况又有些不同,例如调用 os.execute("sleep 1"), ngx.sleep(1), shell.run([[sleep 1]]) 时会产生非常不同的影响。第一个 os.execute 是原生 Lua 提供用于命令调用的阻塞 API,第二个是 OpenResty 提供的非阻塞 API,第三个是 OpenResty 新版1.15中提供的非阻塞 shell 调用。使用 sleep 暂停睡眠还可以做成非阻塞,那后续执行什么?这似乎有点不可思议!

    这是因为,基于Nginx的模型,OpenResty 代码是执行在一个进程中的不同协程中,这时的阻塞和非阻塞是针对这整个进程而言的,第一个阻塞 API 即 os.execute("sleep 1") 会指让整个进程处于休眠状态,使 CPU 空闲(如果对核心进行了亲和性绑定),而调用后两种非阻塞 API,则当前协程通过 yield 进行让步,使调度器执行别的协程,直到满足执行条件后再回来 resume。

    参考:

    https://stackoverflow.com/questions/2625493/asynchronous-vs-non-blocking

    https://moonbingbing.gitbooks.io/openresty-best-practices/content/ngx_lua/sleep.html

    Share:

    从抄书到开源之巅:章亦春的程序人生

    最近在学习 OpenResty 的过程中,不断出现 agentzh 张亦春的名字,也不断产生好奇:春哥是如何创造这么优秀的项目,以及如何推动这么成功的周边生态,要知道 OpenResty 在国外比国内更流行,不像国内那些大公司以战略和 KPI 推动的所谓开源项目,不仅很少走出国门甚至很少走出关系户。

    看到这篇几年前的春哥的访谈,一顿觉得大牛果然是不一样,中学时代就有那么多神奇的历史,更不用说大学时代就能得到 Perl 发明人的赞扬这类成就。但是一顿刺激恐怕过几天就不剩下什么,况且盲目和别人比较也只是平添心魔(应该与昨天的自己比较),仔细想想我觉得以下两点启发更多:

    第一点,抄书和抄代码。春哥举例到他中学时在没有人教(估计2000年时他也无法上网)的情况下自学《C语言程序设计》,因为看不懂也不知道学习方法,就从第一页开始一个字一个字地手抄,直到觉得不用继续手抄。另一个他是学习 Nginx 源码时,白天上班对着 Kindle 抄源码,晚上回家来回踱步在脑海回想白天抄的代码,直到融会贯通,理解其奥妙。他提到这些方法的奥秘是延缓阅读速度,不会遗漏每一个重要细节:眼到,手到,心到。

    这点我也逐步领悟到,慢其实是一种快,很多时候追求速度,长期看反而是最慢的路径,比如很多基础课程(像操作系统、网络、体系),看一堆速成和浅薄的教程,也不如静下心来啃一本系统的大部头收获更多。另外对于自己经常面对的领域技术,如果每次通过速成解决当前问题,那今后也会遇到更多问题并且不断反复,反而更应该花时间系统性的通读文档或源码等。

    第二点,始终保护好最初对编程的好奇和兴趣。主流技术和思想在不断变化,同时每个人都有最适合自己的成长道路,在这种情况下只有向内追寻和坚持,才能逐步积累出自己独特的东西,而这也正是坚持的正向反馈。

  • 相关阅读:
    hdu 3342 Legal or Not 拓排序
    hdu 1596 find the safest road Dijkstra
    hdu 1874 畅通工程续 Dijkstra
    poj 2676 sudoku dfs
    poj 2251 BFS
    poj Prime Path BFS
    poj 3278 BFS
    poj 2387 Dijkstra 模板
    poj 3083 DFS 和BFS
    poj 1062 昂贵的聘礼 dijkstra
  • 原文地址:https://www.cnblogs.com/pyx0/p/13768874.html
Copyright © 2011-2022 走看看