【第02题】给定 n,求 1 + 2 + 3 + ... + n 的和 | 四种解法

100 篇文章 538 订阅 ¥999.99 ¥99.90

零、写在前面

  目前本专栏正在进行优惠活动,在博主主页添加博主好友(好友位没有满的话),可以获取 付费专栏优惠券
  今天是学习 「 C语言 」 打卡的第二天,学习方式很简单,每天我会提供一篇文章供群成员阅读,阅读完本文,做完课后的 「习题练习 」 ,在 万人千题 社区对应的 「 打卡帖 」 下打卡,今天的任务就算完成了。
  很多人问,打卡的时候提示需要填写一个 「 链接 」,可以不用理会,直接提交 「 打卡 」 二字。也可以填写自己对今天打卡的 「 心得和感悟 」,或者 「 解题报告 」
  因为大家都在学习,所以一旦遇到问题都可以在群里问,群成员能够做出更加快速的反馈,高效的达成学习的目的。学有余力的同学可以在 万人千题 社区发布每天练习的解题报告。

一、题目描述

  循环输入,每输入一个正整数 n ( n ≤ 65535 ) n (n \le 65535) n(n65535),输出 1 + 2 + 3 + . . . + n 1 + 2 + 3 + ... + n 1+2+3+...+n 的值,并且多输出一个空行。当没有任何输入时,结束程序。

  • 这个题中,你将会学到以下的内容:

二、解题思路

难度:🔴⚪⚪⚪⚪

  • 由于 n ≤ 65535 n \le 65535 n65535,不是很大,所以我们完全可以通过循环的方式遍历 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)=6553565536=(2161)216=232216,而 i n t int int 能够表示的最大值为 2 31 − 1 2^{31}-1 2311,所以产生了溢出。就变成了负数。至于为什么溢出会变成负数,可以了解补码相关的知识:计算机补码详解
  • 接下来介绍四种正确做法。

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就是1n的数的累加和);
  • ( 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)nn
  • 也就是根据奇偶性来决定是用 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,2321],当 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)=232216<2321
  • 所以不需要担心溢出问题。

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,2631],所以也是能够涵盖 n n n 最大的情况的。

五、推荐专栏

🌌《算法零基础100讲》🌌

六、习题练习

序号题目链接难度
1求1+2+…+n★☆☆☆☆
2Sum Problem★★☆☆☆
3和为s的连续正数序列★★☆☆☆
👇🏻 关注公众号 观看 精彩学习视频👇🏻
  • 59
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论
### 回答1: 目描述: 给定一个正整数n,1/1+1/2+1/3+...+1/n的和。 解思路: 使用循环遍历1到n,将每个数的倒数加起来即可。 代码实现: ```python n = int(input("请输入一个整数:")) sum = for i in range(1, n+1): sum += 1/i print("1/1+1/2+1/3+...+1/n的和为:", sum) ``` 输出示例: ``` 请输入一个整数:5 1/1+1/2+1/3+...+1/n的和为: 2.283333333333333 ``` ### 回答2: 这道目其实考察的是一个数学知识——等差数列求和公式,所以我们先来回顾一下。 设一个等差数列的首项为a1,公差为d,项数为n,那么这个等差数列的和Sn可以表示为: Sn = (n/2)(a1 + an) 其中,an表示这个等差数列的第n项。 那么,回到这道目中,我们可以发现,这个要的n分之一序列是一个等差数列,因为序列中每一项都是前一项除以n得到的。 我们设这个等差数列的首项为1,公差为1/n,项数为n,那么这个等差数列的第n项an可以表示为: an = 1/n 那么,我们就可以利用等差数列求和公式来出这个等差数列的和Sn了: Sn = (n/2)(a1 + an) = (n/2)(1 + 1/n) = n/2 + 1/2 因此,n分之一序列前n项和就是n/2 + 1/2。 需要注意的是,在计算时,我们要保留小数点后的数字,因为这个结果可能会是一个分数或者是一个无理数。 ### 回答3: 这道我们计算一个分数数列的前 n 项和,即 1/n+1/(n+1)+…+1/(2n-1)+1/(2n)。 首先,我们可以将每一项的分母表示为 n+i-1,其中 i 表示在序列中的位置,即第一项 i=1,第二项 i=2,以此类推。 因此,我们可以得到求和式为 1/n+1/(n+1)+…+1/(2n-1)+1/(2n) = (1/n+1/(n+1))+…+(1/(2n-1)+1/(2n))。 接下来,我们将每一对括号中的两个数相加并化简,得到: (1/n+1/(n+1))+(1/(n+2)+1/(n+3))+…+(1/(2n-2)+1/(2n-1))+1/(2n) 再将每一对括号中的两个数的和化简为 (2n+i-1)/(n(i+n-1)),即可得到原式的简化形式: (2n+1)/(n(2n+1)) 因此,要计算原式的值,只需将上式中的 n 替换为给定的 n,即可得到答案。 总结来说,这道虽然涉及分数数列求和,但是通过一定的数学思维和演算,我们可以简化求和式,并得到规律,从而得到解法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值