【发布时间】:2021-10-06 10:31:47
【问题描述】:
我正在解决this Project Euler question。首先我尝试了蛮力,它花了 0.5 秒,然后我尝试了动态编程来利用记忆化,预计会有很大的改进,但我惊讶的是结果是 0.36 秒。
经过一番谷歌搜索后,我发现您不能在函数 (find_collatz_len) 中使用指向外部地图数据 (备忘录) 的指针。因此,每次运行下面的函数时,它都会复制整个字典。这听起来像是对处理器能力的巨大浪费。
我的问题是什么是解决方法,以便我可以使用指向函数外部映射的指针来避免复制。
这是我丑陋的代码:
package main
//project euler 014 - longest collatz sequence
import (
"fmt"
"time"
)
func find_collatz_len(n int, memo map[int]int) int {
counter := 1
initital_value := n
for n != 1 {
counter++
if n < initital_value {
counter = counter + memo[n]
break
}
if n%2 == 0 {
n = int(float64(n)/2)
} else {
n = n*3+1
}
}
memo[initital_value] = counter
return counter
}
func main() {
start := time.Now()
max_length := 0
number := 0
current_length := 0
memo := make(map[int]int)
for i:=1; i<1_000_000; i++ {
current_length = find_collatz_len(i, memo)
if current_length > max_length {
max_length = current_length
number = i
}
}
fmt.Println(max_length, number)
fmt.Println("Time:", time.Since(start).Seconds())
}
【问题讨论】:
-
“所以每次运行下面的函数时,它都会复制整个字典。” -- 不,这不是正在发生的事情。
-
不存在“映射指针问题”。如果你愿意,你可以使用指针,这里没有理由。
-
"item is not scriptable" -- 不是来自 Go 编译器或运行时的实际错误消息,因此很难确定您遇到的实际错误是什么.在不知道实际错误的情况下,我们无法提供如何修复它的建议。
-
就优化而言,您可以使用
make(map[int]int, 1_000_000)将地图初始化为其最终大小,从而避免运行时动态增长地图。 (这将我机器上的时间缩短了近一半 [从 ~0.28 到 ~0.16]) -
地图已经是底层的指针。传递一个映射值将传递一个指针。正如@mkopriva 所建议的,使用预期的最终容量初始化地图:
make(map[int]int, 1_000_000)。这会将运行时间从 0.3 秒减少到 0.2 秒。您也可以将int(float64(n)/2)替换为n/2,因为在您使用的整数范围内,它们会给出相同的结果。这将使您进一步提高 5%(在我的机器上为 0.19 秒)。
标签: algorithm dictionary go