自用 LeetCode 刷题流程

自用 LeetCode 刷题流程

刷 LeetCode 除了把题目做完,还包括了测试用例、整理代码等等繁琐的操作,磨刀不误砍柴工,今天分享一下我自己刷题的流程。

我做 LeetCode 的题目基本上不会使用 LeetCode 网页自带的编辑器环境,我主要使用 Swift 刷题,所以我都是用 Xcode 的环境来刷题。别人不用 LeetCode 自带编辑器的原因我不清楚,对我来说,主要就是,大部分题目我还是需要有一个单步调试的过程才能写完。

我会在本地创建一个和 LeetCode 中 Swift 模版一模一样的 Solution 类,这个类就是解题要用的代码,还要创建一个 main.swift ,作为测试和程序的入口。除此之外,LeetCode 还会有很多链表、树的题目,会涉及到 ListNodeTreeNode 两个类,所以我们最好也在本地提前建好这两个类的代码。完工后我的本地文件是这样的:

文件结构

TreeNodeListNode 的代码每次写相关题目的时候 LeetCode 都会给我们,也基本上不会有变化,我们只需要复制一次就可以一直重复使用了。但其实它给的代码不好用,以 ListNode 为例,如果我们要创建一个链表,我们要写如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
public class ListNode {
public var val: Int
public var next: ListNode?
public init(_ val: Int) {
self.val = val
self.next = nil
}
}
*/

var head: ListNode? = ListNode(0)
head?.next = ListNode(1)
head?.next?.next = ListNode(2)
head?.next?.next?.next = ListNode(3)

链表短还行,如果长了,写起来就是一连串的next、next,更别说如果要添加多个测试用例了。所以我给 ListNode 写了一个新的方法,通过传入数组就可以构造一个 ListNode

另外还有一个问题,调试的时候无法使用 ListNodedescription 属性简单的查看 ListNode 当前的值,例如一个链表依次由1-5的数字构成,我们希望直接能直接以形如”1 2 3 4 5“这样的格式来输出调试信息。如果直接使用 debugDescription 属性,只会看到 Optional(YourProjectName.ListNode) 这样毫无意义的调试信息,我们需要让 ListNode 遵守 CustomStringConvertible 协议,然后添加一个叫做 description 的计算属性,在这个计算属性中我们规定如何格式化输出一个 ListNode

最终完成改造后,我的 ListNode 类长这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class ListNode {
public var val: Int
public var next: ListNode?
public init(_ val: Int) {
self.val = val
self.next = nil
}

static func initListNodeUseArray(array: [Int]) -> ListNode? {
let result: ListNode? = ListNode(Int.max)
var head = result
for num in array {
head?.next = ListNode(num)
head = head?.next
}
return result?.next
}
}

extension ListNode: CustomStringConvertible {
public var description: String {
return "\(val.description) \(next?.description ?? "")"
}
}

这一次,再构建上文的 ListNode,我们只需要这么写:

1
var head = ListNode.initListNodeUseArray(array: [0,1,2,3])

要创建测试用例集合也很容易:

1
2
3
4
5
var cases = [ListNode?]()
cases.append(ListNode.initListNodeUseArray(array: [1,2,3,4,5]))
cases.append(ListNode.initListNodeUseArray(array: [1,1,3,3,4,4,5]))
cases.append(ListNode.initListNodeUseArray(array: [1,1,1,2,3]))
cases.append(ListNode.initListNodeUseArray(array: [1,1]))

还可以方便的输出格式化的 ListNode

1
2
print(ListNode.initListNodeUseArray(array: [1,2,3,4,5])?.description)
// Optional("1 2 3 4 5 ")

对于 TreeNode 类也可以进行类似的改造,这样改造过以后,对于我们在本地调试链表和树这两个类型的题目会带来极大的便利。


做完题目以后,我有整理代码,将所有做过的题单独放到一个文件夹并且上传到 GitHub 的习惯。解题的时候代码文件叫做 Solution.swift,整理到一起以后显然不能再叫这个没有意义的名字,对于一个题目我会标注题号,中文名和题目函数的名称,方便检索,例如第一题两数之和,我会将代码题解文件命名为 [1]两数之和TwoSum.swift,所有题目都使用这一个统一的格式。

问题来了,从工程文件夹将代码文件复制到我们汇总题解的文件夹、重命名文件、git addgit commitgit push 这一套操作并不优雅,更何况 git commit 的时候还要再写一次文件名,所以我用这学期学的 Shell 脚本语言写了一个脚本操作这一套流程,我只要执行写好的脚本,输入格式化后的文件名就行了。

执行脚本

脚本的代码非常简单,但是对我个人来说大大简化了工作流程,这一点上我还是挺满意的。

1
2
3
4
5
6
7
8
echo "输入文件名:"
read FILENAME
cd Documents/Code/Swift/LeetCodeSolution/LeetCodeSolution
cp Solution.swift ../../../LeetCode-Solution/$FILENAME.swift
cd ../../../LeetCode-Solution
git add .
git commit -m "Create $FILENAME.swift"
git push

这么改造完以后啥都好,就是不会做的题还是不会做。(完)


自用 LeetCode 刷题流程
https://wenchanyuan.com/leetcode_workflow/
作者
蟾圆
发布于
2020年8月16日
许可协议