优化1到n求和算法:递归与循环的性能改进问询
1到n求和的优化方案探讨
需求是实现1+2+…+n的求和计算,n的取值范围为1 ≤ N ≤ 10^9,需满足时间限制要求。已知公式n*(n+1)/2可行,但希望了解更复杂的替代方案。
尝试过的实现方式
最初的递归实现
递归方案在n较大时会触发栈溢出异常:
int recur( int n ) { if (n > 0) { return n + recur( n - 1 ) ; } else { return 0 ; } } int main() { int n ; cin >> n ; cout << recur(n) ; }
改进的分情况实现
将n<10000时用递归,n≥10000时用循环,结果正确但n取最大值时运行明显缓慢:
#include<iostream> using namespace std; int recur( int n ) { if (n > 0) { return n + recur( n - 1 ) ; } else { return 0 ; } } void verylong( int n ) { long long sum = 0; for( int i = 0 ; i <= n ; i++ ) { sum += i ; } cout << sum ; } int main() { int n ; cin >> n ; if( n < 10000 ){ cout << recur(n) ; } else{ verylong(n) ; } }
疑问
当前结果正确,但n取最大值时运行明显缓慢,如何优化?是否有更优的替代方案?另外,了解到循环展开方案但不知如何应用于该求和场景。
优化方案解答
1. 循环展开的具体应用
循环展开的核心是减少循环迭代次数,降低循环控制的开销。针对求和场景,我们可以一次处理多个连续数的和,比如每次处理4个数:
void optimized_loop(long long n) { long long sum = 0; long long i; // 批量处理每4个连续数 for (i = 1; i <= n - 3; i += 4) { sum += i + (i+1) + (i+2) + (i+3); } // 处理剩余不足4个的数 for (; i <= n; ++i) { sum += i; } cout << sum << endl; }
这种方式把循环次数降到原来的1/4,能显著减少大n时的运行时间,你也可以根据CPU特性调整每次处理的数的数量(比如8个),进一步提升效率。
2. 分治递归方案(避免栈溢出)
普通递归栈溢出是因为递归深度等于n,改用分治递归可以把深度降到log₂(n)级别(比如n=1e9时深度仅约30),完全不会触发栈溢出:
long long divide_conquer(long long n) { if (n == 0) return 0; if (n == 1) return 1; long long half = n / 2; // 拆分成前half个数和后n-half个数,后段每个数比前段对应数大half,所以后段和=前段和 + half*(n-half) return divide_conquer(half) + divide_conquer(n - half) + half * (n - half); }
这个方案的时间复杂度是O(logn),远快于普通递归和单循环。
3. 必须强调:公式法仍是最优解
虽然你想要复杂替代方案,但不得不说,n*(n+1)/2是时间复杂度O(1)的绝对最优解,只需要一次乘法和一次除法,无论n多大都能瞬间完成计算。只需要注意用long long类型避免溢出(1e9*(1e9+1)=1e18+1e9,在64位整数范围内完全安全):
int main() { long long n; cin >> n; cout << n * (n + 1) / 2 << endl; }
内容的提问来源于stack exchange,提问作者Star
相关产品推荐
相关产品推荐

