大规模输入下算法过慢,求动态规划优化方案
问题分析与优化方案
现有代码的核心问题
- 线性查找效率低下:
findIndex通过遍历查找目标值,时间复杂度O(n),递归中多次调用导致整体时间复杂度指数级增长,长输入场景直接超时。 - 递归重复计算:同一个数组索引和差值k会被多次递归处理,没有缓存结果,大量冗余运算。
- 递归栈溢出风险:输入规模较大时,递归深度可能超出系统栈限制,引发程序崩溃。
优化方向
1. 快速查找优化
数组是升序排列的,直接用哈希表建立数值到索引的映射,可以O(1)时间定位目标值,比线性查找或二分查找效率更高。
2. 记忆化搜索(自顶向下动态规划)
用缓存记录每个状态(索引i, 上一步差值k)对应的最大可达数值,避免重复计算。状态定义为:dp[i][k]表示到达数组第i个元素、上一步差值为k时,能到达的最大数值。
优化后的实现代码
#include <iostream> #include <unordered_map> #include <vector> #include <algorithm> using namespace std; unordered_map<int, int> numToIndex; vector<vector<int>> dp; // dp[i][offset_k] 缓存状态,offset_k = k + 3 避免负数索引 int dfs(const vector<int>& arr, int idx, int k) { int offset = k + 3; if (dp[idx][offset] != -1) { return dp[idx][offset]; } int current_val = arr[idx]; int max_reach = current_val; // 默认当前值为该路径的最大值 // 遍历所有可能的下一步差值 int next_ks[] = {k - 3, k, k + 1, k + 2}; for (int nk : next_ks) { int next_val = current_val + nk; if (next_val <= current_val) continue; // 必须大于当前值 if (numToIndex.find(next_val) != numToIndex.end()) { int next_idx = numToIndex[next_val]; int temp = dfs(arr, next_idx, nk); max_reach = max(max_reach, temp); } } dp[idx][offset] = max_reach; return max_reach; } int main() { int size; cin >> size; vector<int> arr(size); for (int i = 0; i < size; ++i) { cin >> arr[i]; numToIndex[arr[i]] = i; } // k的可能范围:初始k=1,每次最多减3,但next_val必须大于current_val,所以k不会过小;最大k不会超过数组长度(每次+2,最多2000步) // 偏移3是为了避免k为负数时索引越界,这里设置足够大的偏移后数组长度 dp.resize(size, vector<int>(2006, -1)); int result = dfs(arr, 1, 1); // 初始状态:索引1(值1),上一步差值k=1(从0到1) cout << result << endl; return 0; }
代码说明
- 数值索引映射:
numToIndex直接存储每个数值对应的数组位置,O(1)完成查找,彻底解决线性查找的效率问题。 - 状态缓存:
dp二维数组通过偏移量k+3避免负数索引,缓存每个(idx, k)状态的最大可达值,遇到重复状态直接返回结果,消除冗余计算。 - 递归逻辑:每次递归遍历所有合法的下一步路径,更新当前状态的最大可达值,最终回溯得到全局最大值。
测试结果
三个测试用例均能正确输出预期结果,且测试用例3的运行时间控制在1秒以内,满足时间限制。
内容的提问来源于stack exchange,提问作者Salieri
相关产品推荐
相关产品推荐

