第02题给定 n,求 1 + 2 + 3 + ... + n 的和 | 四种解法
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第02题给定 n,求 1 + 2 + 3 + ... + n 的和 | 四种解法相关的知识,希望对你有一定的参考价值。
📢博客主页:https://blog.csdn.net/WhereIsHeroFrom
📢欢迎各位 👍点赞 ⭐收藏 📝评论,如有错误请留言指正,非常感谢!
📢本文由 英雄哪里出来 原创,转载请注明出处,首发于 🙉 CSDN 🙉
作者的专栏:
👉C语言基础专栏《光天化日学C语言》
👉C语言基础配套试题《C试题100例》
👉算法进阶专栏《夜深人静写算法》
一、题目描述
循环输入,每输入一个正整数 n ( n ≤ 65535 ) n (n \\le 65535) n(n≤65535),输出 1 + 2 + 3 + . . . + n 1 + 2 + 3 + ... + n 1+2+3+...+n 的值,并且多输出一个空行。当没有任何输入时,结束程序。
二、解题思路
难度:🔴⚪⚪⚪⚪
- 由于 n ≤ 65535 n \\le 65535 n≤65535,不是很大,所以我们完全可以通过循环的方式遍历 1 到 n n n,然后将遍历到的数字加和后进行输出。这样的时间复杂度是 O ( n ) O(n) O(n) 的。有关于时间复杂度相关的介绍,可以参考这篇文章:一文搞懂算法时间复杂度。
- 当然,这是一个等差数列的求和公式,所以有:
- 1 + 2 + 3 + . . . + n = n ( n + 1 ) 2 1 + 2 + 3 + ... + n = \\frac {n (n+1) } 2 1+2+3+...+n=2n(n+1)
- 这样,只要知道 n n n 的值,就可以在 O ( 1 ) O(1) O(1) 的时间内求得最终的答案了。接下来,让我们来看下代码如何实现。
三、代码详解
1、错误解法
#include <stdio.h>
int main() {
int n;
while (scanf("%d", &n) != EOF) {
int ans = n * (n + 1) / 2; // (1)
printf("%d\\n\\n", ans);
}
return 0;
}
- ( 1 ) (1) (1) 这行代码直接套用等差数列求和公式。但是这里有一个小问题。
- 因为当 n n n 取最大值 65535 65535 65535 时, n ∗ ( n + 1 ) = 65535 ∗ 65536 = ( 2 16 − 1 ) 2 16 = 2 32 − 2 16 n * (n + 1) = 65535 * 65536 = (2^{16}-1)2^{16} = 2^{32} -2^{16} n∗(n+1)=65535∗65536=(216−1)216=232−216,而 i n t int int 能够表示的最大值为 2 31 − 1 2^{31}-1 231−1,所以产生了溢出。就变成了负数。至于为什么溢出会变成负数,可以了解补码相关的知识:计算机补码详解。
- 接下来介绍四种正确做法。
2、正确解法1:循环枚举
#include <stdio.h>
int main() {
int n, ans;
while (scanf("%d", &n) != EOF) {
ans = 0; // (1)
while(n) { // (2)
ans += n; // (3)
--n; // (4)
}
printf("%d\\n\\n", ans);
}
return 0;
}
-
(
1
)
(1)
(1) 初始化结果
ans
为0; -
(
2
)
(2)
(2) 用一个
while
语句来执行循环,一直自减n
,直到n
减为零为止; -
(
3
)
(3)
(3) 将当前
n
的值累加给ans
(循环完毕,ans
就是1
到n
的数的累加和); -
(
4
)
(4)
(4)
--n
等价于n = n - 1
; - 这种方法,就是普通的枚举,正确性容易保证,但是时间复杂度略高,为 O ( n ) O(n) O(n)。
3、正确解法2:奇偶性判断
#include <stdio.h>
int main() {
int n, ans;
while (scanf("%d", &n) != EOF) {
if(n % 2 == 0) { // (1)
ans = n / 2 * (n+1); // (2)
} else { // (3)
ans = (n+1) / 2 * n; // (4)
}
printf("%d\\n\\n", ans);
}
return 0;
}
- 由于 n n n 和 n + 1 n+1 n+1 的奇偶性必然不同,所以两者相乘必然能被 2 整除。
- 所以我们可以得到如下情况:
- s u m ( n ) = { ( n + 1 ) / 2 × n n 为 奇 数 n / 2 × ( n + 1 ) n 为 偶 数 sum(n) = \\begin{cases} (n+1)/2 \\times n & n 为奇数 \\\\ n/2 \\times (n+1) & n 为偶数\\end{cases} sum(n)={(n+1)/2×nn/2×(n+1)n为奇数n为偶数
- 也就是根据奇偶性来决定是用 n n n 去除 2,还是 n + 1 n+1 n+1 去除 2,从而避免溢出。
-
(
1
)
(1)
(1)
%
在C语言中是取模的意思,a%b
代表a除上b得到的余数,a%2 == 0
则代表 a 为偶数,否则为奇数;这里的if
判断代表n
是偶数; -
(
2
)
(2)
(2)
n
为偶数时,n
能被 2 整除,所以先计算n/2
,再乘上n+1
; -
(
3
)
(3)
(3) 这里用到了
else
语句,代表接下来要进行n
为奇数的处理; -
(
4
)
(4)
(4)
n
为奇数时,n+1
能被 2 整除,所以先计算(n+1)/2
,再乘上n
;
4、正确解法3:无符号整型
#include <stdio.h>
int main() {
unsigned int n;
while (scanf("%u", &n) != EOF) {
unsigned int ans = n * (n + 1) / 2; // (1)
printf("%u\\n\\n", ans);
}
return 0;
}
- ( 1 ) (1) (1) 由于无符号整型的范围为 [ 0 , 2 32 − 1 ] [0, 2^{32}-1] [0,232−1],当 n = 65535 n = 65535 n=65535 时,有:
- n × ( n + 1 ) = 2 32 − 2 16 < 2 32 − 1 n \\times (n+1) = 2^{32} -2^{16} \\lt 2^{32}-1 n×(n+1)=232−216<232−1
- 所以不需要担心溢出问题。
5、正确解法4:64位整型
#include <stdio.h>
int main() {
long long n;
while (scanf("%lld", &n) != EOF) {
long long ans = n * (n + 1) / 2; // (1)
printf("%lld\\n\\n", ans);
}
return 0;
}
-
(
1
)
(1)
(1)
long long
是C语言中的64位整型,范围比int大了一个平方量级,在 [ − 2 63 , 2 63 − 1 ] [-2^{63}, 2^{63}-1] [−263,263−1],所以也是能够涵盖 n n n 最大的情况的。
四、扩展阅读
编号 | 知识点 | 链接 |
---|---|---|
1 | 输入 | 光天化日学C语言(05)- 格式化输入 |
2 | 输出 | 光天化日学C语言(04)- 格式化输出 |
3 | 变量声明 | 光天化日学C语言(03)- 变量 |
4 | #define 宏 | 光天化日学C语言(08)- 常量 |
5 | + 、% 算术运算符 | 光天化日学C语言(09)- 算术运算符 |
6 | == 、!= 关系运算符 | 光天化日学C语言(10)- 关系运算符 |
7 | 表达式 | 待更新 |
8 | while循环 | 待更新 |
9 | if 语句 | 待更新 |
10 | break关键字 | 待更新 |
11 | 函数 | 待更新 |
12 | 头文件 | 待更新 |
📢博客主页:https://blog.csdn.net/WhereIsHeroFrom
📢欢迎各位 👍点赞 ⭐收藏 📝评论,如有错误请留言指正,非常感谢!
📢本文由 英雄哪里出来 原创,转载请注明出处,首发于 🙉 CSDN 🙉
作者的专栏:
👉C语言基础专栏《光天化日学C语言》
👉C语言基础配套试题《C试题100例》
👉算法进阶专栏《夜深人静写算法》
以上是关于第02题给定 n,求 1 + 2 + 3 + ... + n 的和 | 四种解法的主要内容,如果未能解决你的问题,请参考以下文章
规律题-----求给定范围内约数的个数 wannafly2017-12-15 A
第25题给定 n,求所有 1 ... n 的全排列 (更新中)
第34题给定一个 n X n 的矩阵 和 R,求旋转 90R 度以后的矩阵(更新中)