【发布时间】:2020-12-28 12:17:37
【问题描述】:
我正在尝试解决问题#14 of Project Euler。 所以主要目标是找到 Collatz 序列的长度。
首先我解决了常规循环的问题:
compute <- function(n) {
result <- 0
max_chain <- 0
hashmap <- 1
for (i in 1:n) {
chain <- 1
number <- i
while (number > 1) {
if (!is.na(hashmap[number])) {
chain <- chain + hashmap[number]
break
}
if (number %% 2 == 0) {
chain <- chain + 1
number <- number / 2
} else {
chain <- chain + 2
number <- (3 * number + 1) / 2
}
}
hashmap[i] <- chain
if (chain > max_chain) {
max_chain <- chain
result <- i
}
}
return(result)
}
n = 1000000 只需 2 秒。
我决定将while循环替换为递归
len_collatz_chain <- function(n, hashmap) {
get_len <- function(n) {
if (is.na(hashmap[n])) {
hashmap[n] <<- ifelse(n %% 2 == 0, 1 + get_len(n / 2), 2 + get_len((3 * n + 1) / 2))
}
return(hashmap[n])
}
get_len(n)
return(hashmap)
}
compute <- function(n) {
result <- 0
max_chain <- 0
hashmap <- 1
for (i in 1:n) {
hashmap <- len_collatz_chain(i, hashmap)
print(length(hashmap))
if (hashmap[i] > max_chain) {
max_chain <- hashmap[i]
result <- i
}
}
return(result)
}
此解决方案有效,但运行速度很慢。 n = 10000 差不多 1 分钟。
我想原因之一是R每次调用函数len_collatz_chain时都会创建hashmap对象。
我知道 Rcpp 包,是的,第一个解决方案工作正常,但我不明白我错在哪里。 有什么建议吗?
例如,我的 Python 递归解决方案在 1 秒内使用 n = 1000000
def len_collatz_chain(n: int, hashmap: dict) -> int:
if n not in hashmap:
hashmap[n] = 1 + len_collatz_chain(n // 2, hashmap) if n % 2 == 0 else 2 + len_collatz_chain((3 * n + 1) // 2, hashmap)
return hashmap[n]
def compute(n: int) -> int:
result, max_chain, hashmap = 0, 0, {1: 1}
for i in range(2, n):
chain = len_collatz_chain(i, hashmap)
if chain > max_chain:
result, max_chain = i, chain
return result
【问题讨论】:
-
我相信这是 R 中的所有开销堆栈问题。如果你想坚持使用 R,我敢打赌你使用你声称的 Rcpp
-
或者你可以使用 Reticulate 包在 R 中运行你的 python 代码
标签: r recursion memoization collatz