【发布时间】:2021-12-29 20:15:27
【问题描述】:
首先,我要承认这个问题可能有一个我可以用谷歌搜索的答案,但我纯数学背景让我没有合适的词汇来知道要搜索什么。
我正在用 Go 编写代码并在 LeetCode 上解决这个问题:https://leetcode.com/problems/generate-parentheses/
我能够自己开发解决方案;像往常一样,我开始研究其他人如何解决问题并尝试优化时间和空间。在某个时候,我明白了这一点。
func generateParenthesis(n int) []string {
ans := []string{}
var dfs func([]byte, int, int)
dfs = func(path []byte, o, c int) {
if c == n {
ans = append(ans, string(path))
}
if o < n {
dfs(append(path, '('), o + 1, c)
}
if o > c {
dfs(append(path, ')'), o, c + 1)
}
}
dfs([]byte{}, 0, 0)
return ans
}
LeetCode 说这个解决方案占用了 2.8MB,即 p-88。我一直在寻找其他运行 2.7MB 的解决方案,即 p-100,并最终通过这样做得到了我的解决方案。
func generateParenthesis(n int) []string {
ans := []string{}
var dfs func(*[]string, []byte, int, int, int)
dfs = func(ans *[]string, path []byte, o, c, n int) {
if c == n {
*ans = append(*ans, string(path))
}
if o < n {
dfs(ans, append(path, '('), o + 1, c, n)
}
if o > c {
dfs(ans, append(path, ')'), o, c + 1, n)
}
}
dfs(&ans, []byte{}, 0, 0, n)
return ans
}
这些差异很小,很容易错过;递归 dfs 在第二个版本中需要更多参数。根据我对内存分配的了解,这没有任何意义。我希望向递归函数添加更多变量意味着每次将调用放在堆栈上时都需要分配更多内存。
- 第二个版本增加了一个
int和一个额外的指针。 - LeetCode 可能在 64 位硬件上运行,这意味着
ints 和指针都需要额外的 64 位内存。 - 堆栈上一次对
dfs的最大调用次数为2*n,n可以高达 8 次。
这一切都让我得出结论,第二个版本应该使用 (64 + 64) * 2 * 8 = 2048 位更多内存(可以忽略不计,tbf),但不知何故使用更少。
第一个问题:怎么会这样?
第二个问题:这是否可能特定于 Go 和/或正在使用的编译器?
【问题讨论】: