ARTS 第 23 周

每周完成一个 ARTS:
Algorithm: 每周至少做一个 LeetCode 的算法题
Review: 阅读并点评至少一篇英文技术文章
Tips: 学习至少一个技术技巧
Share: 分享一篇有观点和思考的技术文章


Contents:


Algorithm

88. Merge Sorted Array

题目:88. Merge Sorted Array

难度:Easy

题意:给定两个有序整数数组 nums1nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。

说明:初始化 nums1nums2 的元素数量分别为 mn。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

示例:

Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3

Output: [1,2,2,3,5,6]

要求:原地更改 nums1

解法:

这一题由于有「nums1nums2 都是有序的」这一前提,题目就变得比较简单。要求是将 nums2 插入到 nums1 中,我们就直接对 nums1 进行更改。

我们的思路非常直接,从后往前将 nums2 插入到 nums1 中,挨个比较 nums1[m-1]nums2[n-1] 的元素的大小,如果前者比较大,那么将前者覆盖到 nums1[m+n-1] 的位置,然后 m 自减 1,否则将后者覆盖到 nums1[m+n-1] 的位置,然后 n 自减 1。这样循环到最后,自然就将 nums2 插入到 nums1 中去了。最后,考虑到有可能 nums1 遍历完毕之后,nums2 还没有遍历完,这样的情况下,nums2 中剩下的元素就是两个数组中最小的那几个,由于 nums1 中的所有数字都已经归位,这时候只要将 nums1 中前 n 个数字赋值为 nums2 中剩下的元素即可。另外,如果 nums2 已经遍历完成,n = 0, 那么之前说的替换操作其实也不会执行,这样就可以省去一个「判断 nums2 是否遍历完成」的过程。代码如下

代码:

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        while m > 0 and n > 0:
            if nums1[m-1] > nums2[n-1]:
                nums1[m+n-1] = nums1[m-1]
                m -= 1
            else:
                nums1[m+n-1] = nums2[n-1]
                n -= 1
        nums1[:n] = nums2[:n]

时间复杂度 O(n),空间复杂度 O(1)。


Review

Math in Data Science, Great Developers Never Stop Learning

本周和大家分享两篇文章。

第一篇文章是 Dataquest 上的一篇文章,名为 Math in Data Science,文章讲解了数据科学几大类常用算法的数学基础,包括:朴素贝叶斯、线性回归、逻辑回归、神经网络、K-Means 聚类和决策树。

文章语言比较简单,涵盖面也已经比较广,可以作为入门读物。

第二篇是 Towards Data Science 上的一篇名为 Great Developers Never Stop Learning 的文章。顾名思义,文章标题意为「伟大的开发者从不停止学习」,那么伟大的开发者都是如何学习的呢?作者给出了自己的方法。

  1. 阅读的艺术:书、博客、Twitter
  2. 从狂热的阅读者变为狂热的写作者:To teach is ti learn twice.
  3. 听播客:Herding Code, .NET Rocks!, Hanselminutes, Software Engineering Radio, Coding Blocks, This Week in Tech, Developer Tea, Software Engineering Daily.
  4. 学习在线课程
  5. 熟能生巧:写 prototype 验证想法、小项目、为开源社区做贡献、在线社区、Katas、黑客马拉松活动
  6. 接触同侪:结对编程、code review
  7. 社交活动:参加业界活动、领英、加入职业组织以及本地用户群,甚至建立你自己的人脉网络

Tips

Vim 剪贴板错误缩进的解决办法

在使用 vim 编辑代码的时候,我们经常会遇到这样一个问题:从别处复制来的代码,粘贴到 vim 中之后,代码的缩进就全乱了,像这样:

复制前:

def findmax(a):

    if len(a) == 0:
        return 0

    curr_max = a[0]

    for i in a:
        if i > curr_max:
            curr_max = i

    return curr_max

粘贴后:

这种现象一是特别难看,二是针对 Python 这种对缩进敏感的语言是个大坑,因为 Python 使用缩进来区分代码块。

出现这种现象的原因是,很多人在 .vimrc 中都设置了自动缩进的功能,这时候我们需要使用 :set paste:set nopaste 来解决。

在粘贴代码之前使用 :set paste 来设置粘贴模式,效果如下:

但是这样会取消自动缩进的功能,这时候我们再次 :set nopaste 即可。

有的人会问,那这样每次都要切换很麻烦,不想要每次复制粘贴都要敲一段代码,怎么办呢?

这里提供两种思路,一种是使用插件,这个之后我会介绍,第二种就是 share 部分提到的,同步 vim 和系统剪贴板的方式,直接在 normal 模式下使用 p 来进行粘贴。


Share

同步 Vim 与系统剪贴板,同时解决 Vim 没有 clipboard 编译选项的问题

Vim 的剪贴板使用 register(寄存器)的方式,简单来说就是,在 vim 中复制的文本是存储在一个个寄存器中的,粘贴的时候也是将这个寄存器中的文本粘贴进去。使用特定寄存器的时候,我们需要在复制或剪切之前按下 "{register},即「双引号 + 寄存器名称」来引用该寄存器,然后再进行复制或剪切。

举个例子,我们希望复制一段文字到 a 剪贴板,那么我们在复制之前就按下 "a,然后复制,这样就把选中的内容复制到 a 剪贴板了,我们也可以同时使用一个 b 剪贴板来保存另一段文本。

使用 :reg {register} 来查看寄存器中的内容。

粘贴之前引用该寄存器,即可对该寄存器内容进行粘贴。如 "ap 粘贴 a 寄存器中的内容。

系统剪贴板在 vim 中的寄存器默认名为「加号 +」,所以复制之前引用系统剪贴板即可实现与系统剪贴板同步。

下面介绍另外一种简便的方法。

要实现这个功能,需要你的 vim 编译选项中有 clipboard。这里提供两种方式来检查你的 vim 是否有这个功能。

第一种,进入 vim,使用 :echo has('clipboard') 命令,如果返回值是 1,那么说明你的 vim 版本支持这个 feature,直接看下面的配置方法,如果返回值是 0,那么你需要升级你的 vim,或者重新编译安装。

第二种,在命令行输入 vim --version | grep clipboard,如果你的 clipboard 前面是一个加号 +,那么说明你的 vim 版本支持这个 feature,如果是减号 -,则不支持,需要升级你的 vim。

那么如何升级 vim 呢?

这里建议使用 Homebrew 安装。在命令行中输入以下命令:

brew install vim -- --with-override-system-vi

安装完成之后再查看你的 vim 是否支持 clipboard

这个时候我本人遇到了一个坑,新下载安装的 vim 还是不支持 clipboard。这是因为使用 homebrew 安装的 vim 在 /usr/local/bin/ 这个路径下,而默认的是 /usr/bin/ 路径下的 vim。

在 .vimrc 中添加 alias:

alias vim="/usr/local/bin/vim"

这样你就会使用 homebrew 下载的 vim 来代替默认的 vim 了。

再次检查是否支持 clipboard

最后,在你的 .vimrc 中添加下面一行即可:

set clipboard=unnamed

重启 terminal 即可。