ARTS
ARTS 是陈浩(网名左耳朵耗子)在极客时间专栏里发起的一个活动,目的是通过分享的方式来坚持学习。
每人每周写一个 ARTS:Algorithm 是一道算法题,Review 是读一篇英文文章,Technique/Tips 是分享一个小技术,Share 是分享一个观点。
本周内容
本周的 ARTS 你将看到:
- LeetCode 516 最长回文子序列.
- 来自 Uber 的 Golang 编程规范.
Algorithm
本周的算法题是 LeetCode 516.longest-palindromic-subsequence, 最长回文子序列.
回文序列和会问字符串的最大区别就是序列
是可以不连续的, 但是串
必须是连续的.
所以这道题和之前第 5 题最长回文子串的区别就很明显了, 或者说这道题要求更加宽泛一些.
// 没错我就是抄答案的 https://leetcode-cn.com/problems/longest-palindromic-subsequence/solution/zi-xu-lie-wen-ti-tong-yong-si-lu-zui-chang-hui-wen/
// dp[i][j] 代表 s 的下标冲 i 到 j 范围内的回文子序列长度
// base case: dp[i][i] 代表一个字符一定是回文子序列
func longestPalindromeSubseq(s string) int {
l := len(s)
dp := make([][]int, l)
for i := range dp {
dp[i] = make([]int, l)
}
for i := 0; i < l; i++ {
dp[i][i] = 1
}
for i := l - 1; i >= 0; i-- {
for j := i + 1; j < l; j++ {
if s[i] == s[j] {
dp[i][j] = dp[i+1][j-1] + 2
} else {
dp[i][j] = max(dp[i+1][j], dp[i][j-1])
}
}
}
return dp[0][l-1]
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
Review 文章推荐
本周推荐的英文文章是 Uber 公开的内部 Golang编程规范.
这个规范包括一些 Golang 的编程技巧和惯例, 也包括一些代码格式这种更加表面一些的规范. 下面是我认为比较重要的一些点.
- 使用
golint
和go vet
命令. - 依赖编译对 interface 的实现类型进行判断.
- 注意错误的类型和封装.
- 如果使用原子操作但又觉得官方包太捡漏的话, 可以试试 Uber 对原子操作的封装.
- 少用全局变量.
- 少用匿名组合, 因为匿名组合不得不暴露匿名属性的封装细节, 需要注意的地方比如这些.
- 尽量少用 init() 来做初始化的工作.
- 用 strconv 代替 Sprintf 来做 string 类型转换.
- 少用 string 到 []byte 的类型转换.
- 使用 make 创建 slice 和 map 时最好指定 capacity.
- 使用小写和单数形式明明 package.
- 不对外暴露的包内全局变量, 最好用下划线 _ 开头.
- 使用
if len(s) == 0
而不是if s == nil
来判断 slice 是否为空 - 少用裸参数(字面量参数?)
- 多用反单引号包裹的原生字符串来逃逸特殊符号.
- 使用打表的方式组建单元测试的数据.
- 使用变长函数数组作为配置类型的可选参数
Tip 编程技巧
本周没有技巧.
Share 灵光一闪
本周也没有灵光.
本周阅读列表
-
- Go 携程调度三个角色 GMP
G 结构中包含 stack 相关信息,还有与协程抢占式调度相关的字段 stackguard0,defer 和 -panic 链表。还包括当前 G 占用的线程,调度器相关数据 sched 以及 goid 等等。
M 中包含的字段比较重要的有 g0 和 currg,其中 g0 代表持有调度栈的 G 他会深度参与协程的调度, curg 是在当前线程上运行的用户 G, 这也是操作系统线程唯一关心的两个 Goroutine. 除此之外还有在运行代码的处理器 p、暂存的处理器 nextp 和执行系统调用之前的使用线程的处理器 oldp.
P 的数量通过 GOMAXPROCS 设置,最多只会有 GOMAXPROCS 个活跃的操作系统线程能够正常运行. P 是线程和 Goroutine 的中间层,也会负责调度线程上的等待队列. 它能在 Goroutine 进行一些 I/O 操作时及时切换, 提高线程的利用率. P 本身也有 status 字段代表其状态, 比如_Pidle
代表 P 上的 G 队列为空,_Prunning
代表正在执行用户代码,_Pgcstop
代表 P 被 GC 停止, 等等.
- Go 携程调度三个角色 GMP
- golang自动检测死锁deadlock的实现
一个用于检测死锁的工具, 实现方式就是封装了 Go 的 sync 库的锁, 然后在每次加锁前检测是否有可能死锁.