🙉自律使你自由!🙉
C語言免費動漫教程,和我一起打卡! 🌞《光天化日學C語言》🌞
LeetCode 太難?先看簡單題! 🧡《C語言入門100例》🧡
數據結構難?不存在的! 🌳《畫解數據結構》🌳
閉關刷 LeetCode,劍指大廠Offer! 🌌《算法入門指引》🌌
LeetCode 太簡單?算法學起來! 💜《夜深人靜寫算法》💜
一、題目描述
循環輸入,每輸入一個正整數 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 最大的情況的。

🙉自律使你自由!🙉
C語言免費動漫教程,和我一起打卡! 🌞《光天化日學C語言》🌞
LeetCode 太難?先看簡單題! 🧡《C語言入門100例》🧡
數據結構難?不存在的! 🌳《畫解數據結構》🌳
閉關刷 LeetCode,劍指大廠Offer! 🌌《算法入門指引》🌌
LeetCode 太簡單?算法學起來! 💜《夜深人靜寫算法》💜

