c++ - 更快地生成递归序列(类似于斐波那契)
问题描述
嗨,必须计算一个系列的第 n 项,因为 n 非常大,并且必须尽可能快地完成。
该系列由以下函数定义:
f(0) = 1
f(1) = 1
f(2n) = f(n)
f(2n+1) = f(n) + f(n-1)
我知道我必须使用记忆。我做了这段代码,但问题是大 n 值会导致分段错误。我想尝试做一个 2 值数组版本(就像这里的回复之一中描述的那样),但我没有找到正确的解决方案。
uint64_t f(uint64_t n)
{
uint64_t a[n+2];
uint64_t i;
a[0] = 1;
a[1] = 1;
for(i = 2; i <= n; i++)
{
if (i % 2 == 0)
{
a[i] = a[i / 2];
}
else
{
a[i] = a[i / 2] + a[(i / 2) - 1];
}
}
return a[n];
};
解决方案
我认为递归在这里是正确的想法,因为您只需要最后一个值,它实际上并不依赖于那么多先前的值。最好的情况是,如果您的输入是 2 的幂,例如 2^n。然后你只需要 n 个输入的值。尽管在其他情况下性能更差,但它仍然应该比实际计算所有前面的值要好得多。
编辑:使用评论中要求的特定数字和一个计数器变量来显示所需的评估数量:
EDIT2:当然可以(以及真正的性能提升!)将递归与缓存中间结果结合起来,正如@Bob__ 在他下面的评论中所展示的那样,谢谢!对于未来的读者,这里有递归+缓存的完整版本。使用给定的输入,缓存将 g 所需的评估数量从没有缓存的 12875760616 显着减少到只有 164 的缓存。
#include <iostream>
#include <map>
#include <stdexcept>
static unsigned long count = 0;
static std::map<unsigned long, unsigned long> cache;
static unsigned long g(unsigned long n) {
auto it = cache.find(n);
if (it != cache.end()) {
return it->second;
}
++count;
if (count == 0) {
std::cout << "Integer overflow! Aborting!";
throw std::overflow_error("overflow error!");
}
if (n == 0 or n == 1) {
return 1;
} else if (n % 2 == 0) {
auto a = g(n / 2);
cache.insert({n, a});
return a;
} else {
auto a = g((n - 1) / 2) + g((n - 3) / 2);
cache.insert({n, a});
return a;
}
}
int main() {
try {
std::cout << "result: " << g(123456789012345678) << std::endl;
std::cout << "number of used values: " << count << std::endl;
} catch (std::exception &e) {
std::cout << "An error occured:\n" << e.what() << std::endl;
}
}
推荐阅读
- html - 显示属性中css中-ms的目的是什么
- arrays - VBA Dynamice Array 下标超出范围
- c# - 如果我将 httpClient 作为 Singleton 注入并更改每个用户请求的基本 url,我会遇到麻烦吗?
- java - 如何解决我的 DateTextField 问题?
- typescript - 为什么 typescript typeguard 不适用于对象的内部属性
- php - 如何检查 WooCommerce 插件是否已启用?
- python - Python cron子进程Popen抛出OSError [Errno 2],手动执行时有效
- java - 为什么在数据库中具有“读取”角色的用户无法列出集合?
- vue.js - 在 Vue Router 中根据路由参数加载不同的组件
- node.js - NPM Link:获取安装包的路径