LeetCode 第1题:Two Sum

目录: leetcode | 标签: | 发布时间:

题目

给出一个整数数组,找出其中的两个整数,使相加等于指定整数,并返回这两个整数的索引。

假设每组输入只有一种解法,并且不能重复使用同一个元素。

举例:

给出 nums = [2, 7, 11, 15], target = 9,

因为 nums[0] + nums[1] = 2 + 7 = 9,
所以返回 [0, 1].

思路

最简单也是最直接的想法就是两重循环直接遍历计算就能得到结果,时间复杂度为 \O(n^2)。 但这肯定不是最优解。

题目中提到只会有一种解法,那就意味着不会有重复的整数,不然就会有多解。 既然没有重复的,那用一个哈希来存储数据就最合适了,整数为键,索引为值。 那我们要找两个整数的索引就很方便了,在遍历数组的时候,检查和目标的差值是否在哈希中,有的话就是答案了。

阅读更多>>


[译] Vimscript 有路勤为径 —— 外部命令

目录: vim | 标签: | 发布时间:

外部命令

Vim 遵从 UNIX “做好一件事”的理念。 把所有能想到的功能都塞进编辑器中并不是一个好的办法,而是应该在适当的时候代理给外部命令。

让我们在插件中添加一些和 Potion 编译器的交互,并开始接触 Vim 的外部命令。

编译

首先,我们会添加一个命令来编译并运行当前的 Potion 文件。 有很多方式来做到这个,但目前我们只会简单地使用一个外部命令。

在插件仓库中创建一个 potion/ftplugin/potion/running.vim 文件。 我们会在这里面创建映射,用来编译并运行 Potion 文件。

if !exists("g:potion_command")
    let g:potion_command = "potion"
endif

function! PotionCompileAndRunFile()
    silent !clear
    execute "!" . g:potion_command . " " . bufname("%")
endfunction

nnoremap <buffer> <localleader>r :call PotionCompileAndRunFile()<cr>

第一段代码检查一个储存执行 Potion 命令的全局变量是否设置过,如果没有,则把它储存起来。 我们之前就看过这种检查方式了。

如果 potion 不在 $PATH 中,这会允许用户在 ~/.vimrc 文件中通过添加一行类似 let g:potion_command = "/Users/sjl/src/potion/potion" 的代码来重写它。

最后一行添加了一个缓冲本地的映射,它调用上面定义的函数。 记住,因为这个文件是在 ftdetect/potion 目录中的, 在每次文件的 filetype 被设为 potion 时,都会被运行。

真正的功能在 PotionCompileAndRunFile() 函数中。 继续,保存文件,打开 factorial.pn 然后按下 <localleader>r 来运行映射,看看会发生什么。

如果 potion 在你的 $PATH 中,文件就会被运行,并且会在终端中 (或者,如果你用的是图形界面的 Vim,会在窗口的底部)看到它的输出。 如果看到一个错误说找不到 potion 命令,你就需要在 ~/.vimrc 文件中设置 g:potion_command, 就像上面提到的那样。

让我们看一看 PotionCompileAndRunFile() 函数时如何工作的。

阅读更多>>


[译] Vimscript 有路勤为径 —— Potion 段落移动

目录: vim | 标签: | 发布时间:

Potion 段落移动

既然已经了解了段落移动是如何工作的, 那就让我们在 Potion 文件中把这些命令以某种方式添加到映射中来。

首先,我们需要决定什么是 Potion 文件中的一个“段落”。 现在有两对段落移动命令,所以我们可以提供两种“方案”,而用户可以随意使用一种自己喜欢的。

我们用以下两种方案来定义 Potion 段落开始的位置:

  1. 任何在空行下面、并且首字符不是空白符的行,或者文件的第一行。
  2. 任何首字符不是空白符、包含一个等号、并且以冒号结尾的行。

以下是稍微扩充后的 factorial.pn 文件,并且展示了这些规则会把哪些行作为段落头部:

# factorial.pn                              1
# Print some factorials, just for fun.

factorial = (n):                            1 2
    total = 1

    n to 1 (i):
        total *= i.

    total.

print_line = ():                            1 2
    "-=-=-=-=-=-=-=-\n" print.

print_factorial = (i):                      1 2
    i string print
    '! is: ' print
    factorial (i) string print
    "\n" print.

"Here are some factorials:\n\n" print       1

print_line ()                               1
10 times (i):
    print_factorial (i).
print_line ()

第一种定义更宽松。它把段落大致定义为一段“最高层级的文本块”。

第二种定义更严格。它把段落定义为(实际上就是)函数的定义。

阅读更多>>


[译] Vimscript 有路勤为径 —— 段落移动原理

目录: vim | 标签: | 发布时间:

段落移动原理

如果你从来没用 Vim 的段落移动命令([[]][],以及][),那现在就花点时间来阅读它们的帮助文档。 同时也阅读下 :help section

是不是晕了?没关系,我第一次阅读这些内容也是一样。 我们将通过写代码的方式快速学习这些移动是如何工作的,然后在下一章节,我们会创建自己的 Potion 插件来支持它们。

nroff 文件

这4种“段落移动”命令从概念上来说表示在文件的“段落”之间移动。

这些命令都是被设计出来在nroff 文件中默认就能用的。 nroff 是一种类似 Latex 或者 Markdown 的语言 —— 它用来编写文本,然后进行格式化 (实际上就是 UNIX 帮助文档用到的格式)。

nroff 文件用一系列的“宏”来定义“段落头部”。例如,下面是引用的一段 awk 帮助文档:

.SH NAME                                                     ***
awk \- pattern-directed scanning and processing language
.SH SYNOPSIS                                                 ***
.B awk
[
.BI \-F
.I fs
]
[
.BI \-v
.I var=value
]
[
.I 'prog'
|
.BI \-f
.I progfile
]
[
.I file ...
]
.SH DESCRIPTION                                              ***
.I Awk
scans each input
.I file
for lines that match ...

.SH 开始的行就是段落头部。我用 *** 标记了它们。 这4个段落移动命令会使你的光标在这些段落头部行之间移动。

Vim 把任何以 . 和一个 nroff 头部宏开始的行都当作是段落头部行,即使你并不是在编辑 nroff 文件

你可以通过修改 sections 选项来修改宏,但是 Vim 仍会要求在行开始位置有个区间段, 并且宏必须是配对的字符,所以,这个选项并没有给 Potion 文件带来足够的灵活性。

阅读更多>>


[译] Vimscript 有路勤为径 —— 高级折叠

目录: vim | 标签: | 发布时间:

高级折叠

在上一章节中,我们使用了 Vim 的 indent 折叠来给 Potion 文件添加一些快速但有污染的折叠。

打开 factorial.pn 文件,按下 zM 以确保所有的折叠都关闭了。现在文件应该看上去如下:

factorial = (n):
+--  5 lines: total = 1

10 times (i):
+--  4 lines: i string print

切换第一个折叠,然后会如下:

factorial = (n):
    total = 1
    n to 1 (i):
+---  2 lines: # Multiply the running total.
    total.

10 times (i):
+--  4 lines: i string print

这看上去很棒,但是我个人更喜欢把代码块的第一行和它的内容一起折叠。 在本章节中,我们会编写一些自定义的折叠代码,当我们完成后,这些折叠将会看上去像这样:

factorial = (n):
    total = 1
+---  3 lines: n to 1 (i):
    total.

+--  5 lines: 10 times (i):

这样更紧凑并且易于阅读(对于我来说)。如果你更喜欢 indent 的方式也是可以的, 但是无论如何也请完成本章,这样可以获得一些编写 Vim 折叠表达式的实践经验。

阅读更多>>


[译] Vimscript 有路勤为径 —— 基本折叠

目录: vim | 标签: | 发布时间:

基本折叠

如果你从来没用过 Vim 的代码折叠,那可就错过了一个很棒的功能。 阅读 :help usr_28 并花点时间在平时的工作中尝试着用用。 等你熟悉了之后,再回到本章来。

折叠类型

Vim 支持六种不同的方式来定义文本应该如何折叠。

手动(Manual)

你可以手动创建折叠,Vim 会把它们存储在内存中。 当你关闭 Vim 后,它们就消失了,而下次编辑文件的时候,又得重新创建。

如果结合一些自定义的映射来轻松地创建折叠,那这种方式还算便利。 我们并不会在本书中这样做,但是要有这个概念,如果刚好碰到这种情况,可能会派上用场。

标记(Marker)

Vim 基于实际文本中的字符来折叠代码。

通常,这些字符会放在注释中(例如 // {{{), 但是,在某些语言中,你可以取巧地用些语言本身语法中的东西,比如 Javascript 中的 {}

也许添加一些纯粹为文本编辑器服务的注释会让代码变得杂乱无章,但好处就是让你能为一个指定文件手动创建折叠。 如果你正在处理一个很大的文件,并且想以特殊的方式来组织的话,这将是个非常棒的办法。

差分(Diff)

在处理差分文件时的一种特殊折叠模式。我们不会讨论它,因为 Vim 会自动处理它。

表达式(Expr)

这允许你使用一段自定义的 Vimscript 代码片段来定义在哪里折叠。 这是最强大的方式,但也需要最多的工作。 我们会在下一章节继续讲到它。

缩进(Indent)

Vim 使用代码的缩进来决定折叠位置。 相同缩进的行折叠到一起,只有空白字符的行(以及空行)会并入附近的折叠中。

这实际上可以直接使用,因为代码已经有了缩进;你唯一需要做的就是打开开关。 我们将把它作为 Potion 文件的第一种折叠方式。

阅读更多>>


[译] Vimscript 有路勤为径 —— 更多高级语法高亮

目录: vim | 标签: | 发布时间:

更多高级语法高亮

Vim 的语法高亮是个能轻松得独自撑满一本书的话题。

现在,我们会讲到最后一个重要的点,后面就继续讲其他的内容。 如果你想了解更多,可以通过 :help syntax 阅读 Vim 的文档,或看看别人写的语法文件。

高亮字符串

像大部分编程语言一样,Potion 也支持字符串,例如 "Hello, world!"。 我们要把它们高亮为字符串。要做到这点,我们要使用 syntax region 命令。 把以下代码添加到 Potion 语法文件中:

syntax region potionString start=/\v"/ skip=/\v\\./ end=/\v"/
highlight link potionString String

关闭并重新打开 factorial.pn 文件,你会看到文件末尾的字符串被高亮显示了!

最后一行应该很熟悉了。如果你不知道它做了什么,那就重新阅读之前两个章节。

第一行中,使用了 “region” 来添加语法组。 它有一个 “start” 模式和一个 “end” 模式来分别表示开始和结束的位置。 在本例中,一个 Potion 字符串从一个双引号开始,到下一个双引号结束。

syntax region 中的 “skip” 参数让我们能处理字符串转义,比如 "She said: \"Vimscript is tricky, but useful\"!"

如果我们不用 skip 参数,Vim 会在 Vimscript 前的那个 " 的位置结束字符串,而这不是我们希望的!

简而言之就是,syntax regionskip 参数会告诉 Vim: “虽然你已经开始了范围匹配,但我也想让你忽略任何匹配 skip 的内容,即使它一般是作为范围匹配的结束”。

花几分钟思考思考。如果是 "foo \\" bar" 会发生什么?这是正确的行为么? 这会一直都是正确的行为么?关上书,花几分钟,认认真真地想想

阅读更多>>


[译] Vimscript 有路勤为径 —— 高级语法高亮

目录: vim | 标签: | 发布时间:

高级语法高亮

目前为止,我们已经为 Potion 文件定义了一些简单的语法高亮:关键字和函数。

如果你没做前一章节的练习,最好回去完成它们。我会假设你已经完成了。

实际上,你应该回去完成所有跳过的练习。即使觉得不需要,但为了使这本书发挥效果,你就必须完成它们。 在这一点上,请务必相信我。

高亮注释

Potion 中有个肯定需要高亮的部分就是注释。 问题是 Potion 的注释是以 # 开始的,而这(通常都)不在 iskeyword 内。

如果你不知道 iskeyword 是什么,那就说明你没听我的。回头去做完那该死的练习。 当我为每个章节出练习的时候,并不只是要扔给你们一堆没用的作业。 你真的需要完成它们以便理解本书。

因为 # 不是关键字字符,我们需要用一个正则表达式来匹配它(以及注释的剩余部分)。 我们将用 syntax match ,而非 syntax keyword。 把以下代码添加到语法文件中:

syntax match potionComment "\v#.*$"
highlight link potionComment Comment

我之后不会再让你把代码放到文件中了。你是个程序员:应该自己判断。

关闭并重新打开 factorial.pn。在文件随意位置加上一行注释,你会看到它被高亮为注释了。

第二行很简单:它告诉 Vim 把 potionComment 语法组中的任何东西都高亮为注释。

第一行是新的内容。我们用 syntax match 来让 Vim 匹配正则表达式,而不是字面的关键字。

阅读更多>>


[译] Vimscript 有路勤为径 —— 基本语法高亮

目录: vim | 标签: | 发布时间:

基本语法高亮

既然已经有了模板,那就是时候开始为我们的 Potion 插件写一些有用的代码了。 我们将从一些简单的语法高亮开始。

在插件仓库中创建 syntax/potion.vim 文件。把以下代码放进文件中:

if exists("b:current_syntax")
    finish
endif

echom "Our syntax highlighting code will go here."

let b:current_syntax = "potion"

关闭 Vim,然后打开 factorial.pn 文件。你可能会看到输出的信息,也可能看不到, 这取决于是否有其他插件在它之后执行命令。如果运行 :messages 你会清楚地看到文件的确被载入了。

注意:只要说到打开 Potion 文件,就是指打开一个新的 Vim 窗口或者实例,而不是分割窗口或者标签。 打开新的 Vim 窗口会重新载入所有捆绑的文件,而分割窗口不会。

文件开头和结尾的几行是一种惯例,当语法高亮已经在缓冲区开启后,可以防止重复载入。

阅读更多>>


[译] Vimscript 有路勤为径 —— 探测文件类型

目录: vim | 标签: | 发布时间:

探测文件类型

创建一个 Potion 文件,并作为我们插件的一个示例。 任意地方创建一个 factorial.pn 文件,然后把以下 Potion 代码放进去:

factorial = (n):
    total = 1
    n to 1 (i):
        total *= i.
    total.

10 times (i):
    i string print
    '! is: ' print
    factorial (i) string print
    "\n" print.

这段代码创建了一个简单的阶乘函数,并调用了10次,每次都把结果打印出来。 用 potion factorial.pn 来运行它。输出应该看上去像这样:

0! is: 0
1! is: 1
2! is: 2
3! is: 6
4! is: 24
5! is: 120
6! is: 720
7! is: 5040
8! is: 40320
9! is: 362880

如果你的输出不是这样,或者有报错,那停下来看看哪里出错了。 这段代码应该按原样运行。

花点时间来弄明白这代码是如何运行的。你可以自由翻阅 Potion 的文档。 这对于理解 Vimscript 无关紧要,但是能让你成为更好的程序员。

阅读更多>>

加载更多