ARTS
ARTS 是陈浩(网名左耳朵耗子)在极客工夫专栏里发动的一个流动,目标是通过分享的形式来保持学习。
每人每周写一个 ARTS:Algorithm 是一道算法题,Review 是读一篇英文文章,Technique/Tips 是分享一个小技术,Share 是分享一个观点。
本周内容
这周的 ARTS 你将看到:
- N 皇后网网红题.
- 什么是软件系统适度设计?
Algorithm
本周的算法题是网红面试题 N 皇后问题: LeetCode 51 N-Queens.
这是一道十分经典的应用 回溯 + 剪支 的搜寻类题目, 这道题尽管是 hard 难度, 但我感觉最难得中央在于想到应用深度优先搜寻的办法.
上面是代码, 思路详见正文.
func solveNQueens(n int) [][]string {ans := make([][]int, 0)
// 上面是回溯记忆操作, 用于剪支
// 因为每次回溯都按行 row 从上到下进行, 因而同一行的皇后互斥曾经在回溯流程被排除了
// 只须要思考列和两种对角线
col := make(map[int]struct{}, 0) // 代表列中是否已存在皇后
pie := make(map[int]struct{}, 0) // 代表撇 (右上到左下) 是否已存在皇后
na := make(map[int]struct{}, 0) // 代表捺 (左上到右下) 是否已存在皇后
queens := make([]int, 0)
// i 示意搜寻进行到第 i 行
var dfs func(i int)
dfs = func(i int) {
if i == n {
// 这里必须对 queens 进行深拷贝, 否则后续回溯会影响 ans 中的后果
tmp := make([]int, len(queens))
copy(tmp, queens)
ans = append(ans, tmp)
}
for j := 0; j < n; j++ {_, a := col[j]; _, b := pie[i+j]; _, c := na[i-j]
// 剪支
if !a && !b && !c {col[j], pie[i+j], na[i-j] = struct{}{}, struct{}{}, struct{}{}
queens = append(queens, j)
dfs(i+1)
delete(col, j); delete(pie, i+j); delete(na, i-j)
// 因为底层数据没有变, 所以必须删除本次增加的元素, 后续回溯能力失常应用 queens
queens = queens[:len(queens)-1]
}
}
}
dfs(0)
return genMetric(ans, n)
}
func genMetric(ans [][]int, n int) [][]string {ret := make([][]string, 0)
s := ""
for i := 0; i < n; i++ {s += "."}
for _, queens := range ans {metric := make([]string, 0)
for _, q := range queens {l := []byte(s)
l[q] = 'Q'
metric = append(metric, string(l))
}
ret = append(ret, metric)
}
return ret
}
Review 文章举荐
本周的文章举荐是对于软件架构中的适度设计的: 十个软件系统适度设计的例子.
- 误区一: 工程师比业务方更聪慧.
作者用他十五年的工作教训担保, 相对不存在收敛的业务. 业务这玩意儿只可能越来越多, 越来越发散. 因为增长就是业务的本质特征, 不能怪业务方.
最好记住一点, 业务方永远是爸爸.
- 误区二: 可重用的业务逻辑.
如果只是单纯的通过重用之前的逻辑来构建新的业务逻辑, 即, 在已有的公共逻辑根底上进行横向的扩大. 那么随着业务性能的减少, 零碎会变得越来越简单, 晓得不可保护.
所以, 在依赖公共逻辑进行性能的横向扩大之前, 先对公共局部的逻辑做细分(或者叫纵向划分).
- 误区三: 所有皆泛型.
程序员有时候会被写出优良的形象代码的欲望冲昏了头脑, 以至于为了形象而形象, 升高了代码的可读性却并没有带来多少可维护性.
有时候, 谬误的形象还不如反复的代码重叠.
- 误区四: 对第三方依赖库的封装器性能过于繁多.
对依赖库的封装肯定要思考更换依赖实现的可能, 同时不要在封装中掺杂具体的业务逻辑.
- 误区五: 自觉应用所谓的高级个性和设计准则并不可取.
给每种对象都形象除一个接口(或者抽象类), 或者自觉利用某些看似高级的语法个性. 无脑利用那些高级的软件设计准则, 这样的做法并不可取. 如果只是一个非常简单的小逻辑, 当前复用的可能简直没有, 那么这种状况还是把那些准则和办法忘掉吧. 这些概念不是一般的小工具, 只有场景适合能力发挥作用.
- 误区六: 学会一样技能或者个性就想到处用.
这点有些相似误区五种的意思, 没有场景空谈应用时没有意义的.
- 误区七: 过于崇奉各种 “ity”.
作者列出的一些 “ity” 的例子, Configurability, Security, Scalability, Maintainability, Extensibility.
落实这些概念之前, 肯定要想想目前零碎的实在场景.
- 误区八: 审慎看待企业外部造轮子.
轮子造出来并不是重点, 前期保护的老本也十分高, 决定做这件事件之前肯定要想好.
- 误区九: 依赖零碎现状却从不想重构.
重构是必然的后果, 不存在动不了的代码.
- 误区十: 过分高估本人和团队.
优良的零碎须要优良的开发者和工夫, 而且无论多优良的开发者的开发速度都是有极限的, 又快又好是不存在的.
Tip 编程技巧
本周没有技巧 …
Share 灵光一闪
实践学习只能晋升认知, 只有实际能力出真知.