🔥個人主頁:艾莉絲努力練劍
?專欄傳送門:《C語言》、《數據結構與算法》、C語言刷題12天IO強訓、LeetCode代碼強化刷題、洛谷刷題、C/C++基礎知識知識強化補充、C/C++干貨分享&學習過程記錄
🍉學習方向:C/C++方向
??人生格言:為天地立心,為生民立命,為往圣繼絕學,為萬世開太平
前言:距離我們學完C語言已經過去一段時間了,在學習了初階的數據結構之后,博主還要更新的內容就是【C語言16天強化訓練】,之前博主更新過一個【C語言刷題12天IO強訓】的專欄,那個只是從入門到進階的IO模式真題的訓練。【C語言16天強化訓練】既有IO型,也有接口型。和前面一樣,今天依然是訓練五道選擇題和兩道編程算法題,希望大家能夠有所收獲!
目錄
正文
一、五道選擇題
1.1? 題目1
1.2? 題目2
1.3? 題目3
1.4? 題目4
1.5? 題目5
二、兩道算法題
2.1? 錯誤的集合
題目理解:
2.2??密碼檢查
題目理解:
結尾
正文
一、五道選擇題
1.1? 題目1
題干:設變量已正確定義,以下不能統計出一行中輸入字符個數(不包含回車符)的程序段是()
A.? n=0;while(ch=getchar()!='\n')n++; ? ? B.?n=0;while(getchar()!='\n')n++; ? ?
C. for(n=0;getchar()!='\n';n++);? ? ? ? ? ? ? ?D.?n=0;for(ch=getchar();ch!='\n';n++);
解析:
其他選項都沒有問題,我們看D選項這里,在for循環的初始化部分,ch=getchar()只執行一次(讀取第一個字符),然后循環條件檢查?ch!='\n' 。如果第一個字符不是換行符,則進入循環,但循環體內沒有語句(只有空語句
;)
,且迭代部分n++執行,但沒有再次讀取字符。因此,ch始終是第一個字符,如果第一個字符不是換行符,循環將無限執行,因為ch永遠不改變,導致無限循環和錯誤計數。所以,這個選項不能正確統計字符個數。
因此,不能統計一行中輸入字符個數(不包含回車符)的選項是D。
1.2? 題目2
題干:運行以下程序后,如果從鍵盤上輸入 65 14?<回車> ,則輸出結果為( )
int main()
{int m, n;printf("Enter m,n;");scanf("%d%d", &m,&n);while (m!=n) //1{while(m>n) m=m-n; //2while(n>m) n=n-m; //3}printf("m=%d\n",m);return 0;
}
A. 3? ? ? B. 2? ?? C.? 1? ? D. 0
解析:
我們輸入m=65, n=14,<回車>之后——
第一次外層循環(m != n,65 != 14)
進入內層循環1:m>n(65>14),執行m=m-n多次:
第一次:m=65-14=51
第二次:m=51-14=37
第三次:m=37-14=23
第四次:m=23-14=9(現在m=9, n=14,m<n,退出內層循環1)
進入內層循環2:n>m(14>9),執行n=n-m:
第一次:n=14-9=5(現在n=5, m=9,n<m,退出內層循環2)
此時m=9, n=5(不相等),繼續外層循環。
第二次外層循環(m != n,9 != 5)
內層循環1:m>n(9>5),執行m=m-n:
第一次:m=9-5=4(現在m=4, n=5,m<n,退出)
內層循環2:n>m(5>4),執行n=n-m:
第一次:n=5-4=1(現在n=1, m=4,n<m,退出)
此時m=4, n=1(不相等),繼續外層循環。
第三次外層循環(m != n,4 != 1)
內層循環1:m>n(4>1),執行m=m-n多次:
第一次:m=4-1=3
第二次:m=3-1=2
第三次:m=2-1=1(現在m=1, n=1,m==n,退出內層循環1)
此時m=1, n=1,相等,退出外層循環。
最終輸出m=1。
因此,輸出結果為1,即選項C。
1.3? 題目3
題干:若運行以下程序時,從鍵盤輸入 ADescriptor<回車> ,則下面程序的運行結果是( )
#include <stdio.h>
int main()
{char c;int v0=0,v1=0,v2=0;do{switch(c=getchar()){case'a':case'A':case'e':case'E':case'i':case'I':case'o':case'O':case'u':case'U':v1 += 1;default:v0+= 1;v2+=1;}}while(c!='\n');printf("v0=%d,v1=%d,v2=%d\n",v0,v1,v2);return 0;
}
A.? v0=7,v1=4,v2=7? ? ?B.? v0=8,v1=4,V2=8? ? ?C.?v0=11,v1=4,v2=11 ? ? ?D.??v0=12,v1=4,v2=12
解析:
總共處理了12個字符(包括換行符)——
元音有:' A ',' e ',' i ',' o '(共4個),所以 v1 = 4。
每個字符都會執行default,所以 v0 和 v2 都是12。
所以正確答案就是D。
1.4? 題目4
題干:如下函數是求兩個int數字最大公約數的,指出其中存在的問題【多選】( )
int gcd(char x,char y)
{int min = x < y ? x : y;for (min = 0; min > 0; min--)if (x % min = 0 && y % min = 0)return min;
}
A.?參數類型不對? ? B.?循環變量min初值不對? ? C.?判斷等于的符號不對? ? D.?返回類型不對
解析:
A選項——參數類型不對:函數目的是求兩個整數的最大公約數,但參數類型為char(字符類型),而不是int(整數類型)。雖然char可以視為小整數,但通常最大公約數函數應使用int類型,以處理更大的數字和通用整數。因此,參數類型不正確的確是其存在的問題。
B選項——循環變量min初值不對:在循環中,min被初始化為 0(for(min = 0; ...)),但循環條件為min > 0,因此循環根本不會執行(因為初始值0不滿足min>0)。正確的做法是使用之前計算的 min(即 x 和 y 中的較小值)作為初始值,然后遞減。但這里覆蓋了之前的值,導致邏輯錯誤。
C選項——判斷等于的符號不對:在條件判斷中,if (x % min = 0 && y % min = 0) 使用了賦值運算符?=?而不是相等比較運算符 == 。這會導致編譯錯誤(因為賦值操作不允許在條件中這樣使用)或邏輯錯誤(總是將0賦值給表達式)。正確的應該是 ==。
D選項——返回類型不對:函數返回類型是?int,這本身是合適的,因為最大公約數是整數。但問題在于函數可能沒有返回任何值(如果循環沒有執行,則沒有返回值),這會導致未定義行為。不過,返回類型?int?本身并不是錯誤,但函數設計有缺陷。
因此,所有選項A、B、C都是正確的問題描述。D選項(返回類型不對)可能不是主要問題,但函數確實存在返回類型與邏輯不匹配的風險(可能無返回值)。嚴格來說,D也是問題之一(因為函數可能無法返回正確結果)。
但根據題干“指出其中存在的問題【多選】”,A、B、C是明顯錯誤,D也有問題。
綜上所述,正確答案就是ABCD。
1.5? 題目5
題干:執行下面的程序段,語句3的執行次數為( )
for(i = 0; i <= n-1; i++) // (1)for(j = n; j > i; j--) // (2)state; // (3)
A.?n(n+2)/2 ? ? B.?(n-1)(n+2)/2 ? ? C.?n(n+1)/2 ? ? D.?(n-1)(n+2)
解析:
我們先來分析一下這個嵌套循環——
外層循環:i?從 0?到 n-1(共 n?次迭代)。
內層循環:j?從 n?向下到 i+1(包括),因此內層循環次數為 n - i(因為 j 從 n?到 i+1,步長為1,次數為 n - i)。
語句(3)的執行次數是內層循環的總次數,即對每個 i,內層循環執行 n - i?次。
總次數的計算過程如下所示——
正確選項是C.?n(n+1)/2?。
選擇題答案如下:
1.1? D
1.2? C
1.3? D
1.4? ABCD
1.5? C
校對一下,大家都做對了嗎?
二、兩道算法題
2.1? 錯誤的集合
前面我們都是牛客網的題目,今天終于有一道力扣題目了!
力扣題目鏈接:645. 錯誤的集合??????
力扣題解鏈接:解決【錯誤的集合】問題
題目描述:
題目理解:
我們需要去找出重復的數字和丟失的數字,可以用計數數組。
這道題是接口型的,下面是C語言的模版(如果是IO型就可以不用管它們了)——
代碼演示:
/*** Note: The returned array must be malloced, assume caller calls free().*/
int* findErrorNums(int* nums, int numsSize, int* returnSize) {// 創建計數數組,初始化為0int* count = (int*)calloc(numsSize + 1, sizeof(int));int* result = (int*)malloc(2 * sizeof(int));*returnSize = 2;// 統計每個數字出現的次數for (int i = 0; i < numsSize; i++) {count[nums[i]]++;}// 找出重復的數字和丟失的數字for (int i = 1; i <= numsSize; i++) {if (count[i] == 2) {result[0] = i; // 重復的數字}if (count[i] == 0) {result[1] = i; // 丟失的數字}}free(count);return result;
}
時間復雜度:O(n);
空間復雜度:O(n)。
我們可以改進一下,優化復雜度——
int* findErrorNums(int* nums, int numsSize, int* returnSize) {int* result = (int*)malloc(2 * sizeof(int));*returnSize = 2;long long n = numsSize;long long sum = n * (n + 1) / 2;long long sum_sq = n * (n + 1) * (2 * n + 1) / 6;long long actual_sum = 0;long long actual_sum_sq = 0;for (int i = 0; i < numsSize; i++) {actual_sum += nums[i];actual_sum_sq += (long long)nums[i] * nums[i];}// sum - actual_sum = missing - duplicate// sum_sq - actual_sum_sq = missing^2 - duplicate^2long long diff = sum - actual_sum; // missing - duplicatelong long diff_sq = sum_sq - actual_sum_sq; // missing^2 - duplicate^2// missing + duplicate = diff_sq / difflong long sum_md = diff_sq / diff;result[1] = (diff + sum_md) / 2; // missing numberresult[0] = sum_md - result[1]; // duplicate numberreturn result;
}
時間復雜度:O(n);
空間復雜度:O(1)。
我們學習了C++之后也可以嘗試用C++來實現一下,看看自己前段時間C++學得怎么樣——
用計數數組實現的代碼演示:
class Solution {
public:vector<int> findErrorNums(vector<int>& nums) {int n = nums.size();vector<int> count(n + 1, 0);vector<int> result(2);// 統計每個數字出現的次數for (int num : nums) {count[num]++;}// 找出重復的數字和丟失的數字for (int i = 1; i <= n; i++) {if (count[i] == 2) {result[0] = i; // 重復的數字}if (count[i] == 0) {result[1] = i; // 丟失的數字}}return result;}
};
時間復雜度:O(n),空間復雜度:O(n)。
我們還可以對空間復雜度進行一下優化——
class Solution {
public:vector<int> findErrorNums(vector<int>& nums) {int n = nums.size();long long sum = (long long)n * (n + 1) / 2;long long sum_sq = (long long)n * (n + 1) * (2 * n + 1) / 6;long long actual_sum = 0;long long actual_sum_sq = 0;for (int num : nums) {actual_sum += num;actual_sum_sq += (long long)num * num;}long long diff = sum - actual_sum; // missing - duplicatelong long diff_sq = sum_sq - actual_sum_sq; // missing2 - duplicate2long long sum_md = diff_sq / diff; // missing + duplicateint missing = (diff + sum_md) / 2;int duplicate = sum_md - missing;return {duplicate, missing};}
};
時間復雜度:O(n),空間復雜度:O(1)。
我們目前要寫出來C++的寫法是非常考驗前面C++的學習情況,大家可以嘗試去寫一寫,優先掌握C語言的寫法,博主還沒有介紹C++的算法題,之后會涉及的,敬請期待!
2.2??密碼檢查
題目鏈接:REAL585 密碼檢查
題目描述:
題目理解:
我們將編寫一個C程序來逐個檢查每個密碼,并輸出"YES"或"NO"。
由題意可知,密碼必須滿足以下條件:
1、密碼只能由大寫字母、小寫字母和數字構成;
2、密碼不能以數字開頭;
3、密碼至少包含大寫字母、小寫字母和數字中的兩種類型;
4、密碼長度至少為8。
這道題是IO型的,下面是C語言的模版(如果是IO型就可以不用管它們了)——
代碼演示:
#include <stdio.h>
#include <ctype.h>
#include <string.h>int main()
{int n;scanf("%d", &n);while (getchar() != '\n'); // 清空輸入緩沖區for (int i = 0; i < n; i++) {char password[101];if (fgets(password, sizeof(password), stdin) == NULL) {printf("NO\n");continue;}// 移除換行符和可能的回車符int len = strlen(password);while (len > 0 && (password[len - 1] == '\n' || password[len - 1] == '\r')) {password[len - 1] = '\0';len--;}// 檢查是否為空字符串if (len == 0) {printf("NO\n");continue;}int has_upper = 0, has_lower = 0, has_digit = 0;int valid = 1;// 條件4: 長度至少為8if (len < 8) {valid = 0;}// 條件2: 不能以數字開頭if (isdigit(password[0])) {valid = 0;}// 檢查每個字符for (int j = 0; j < len; j++) {unsigned char c = password[j]; // 使用unsigned char避免符號擴展問題if (isupper(c)) {has_upper = 1;} else if (islower(c)) {has_lower = 1;} else if (isdigit(c)) {has_digit = 1;} else {valid = 0;break;}}// 條件3: 至少包含兩種類型if (valid) {int type_count = has_upper + has_lower + has_digit;if (type_count < 2) {valid = 0;}}printf("%s\n", valid ? "YES" : "NO");}return 0;
}
時間復雜度:O(n*m);
空間復雜度:O(m)。
這個程序存在一定的問題,測試用例只能通過兩個。博主會把最終代碼實現呈現在下面——
時間復雜度:O(n*m);
空間復雜度:O(m)。
我們學習了C++之后也可以嘗試用C++來實現一下,看看自己前段時間C++學得怎么樣——
代碼演示:
#include <iostream>
#include <string>
#include <cctype>
using namespace std;bool isValidPassword(const string& password) {// 檢查長度if (password.length() < 8) {return false;}// 檢查不能以數字開頭if (isdigit(password[0])) {return false;}bool hasUpper = false;bool hasLower = false;bool hasDigit = false;for (char c : password) {// 檢查字符類型if (isupper(c)) {hasUpper = true;} else if (islower(c)) {hasLower = true;} else if (isdigit(c)) {hasDigit = true;} else {// 包含非法字符return false;}}// 檢查至少包含兩種類型int typeCount = (hasUpper ? 1 : 0) + (hasLower ? 1 : 0) + (hasDigit ? 1 : 0);return typeCount >= 2;
}int main()
{int n;cin >> n;cin.ignore(); // 消耗換行符for (int i = 0; i < n; i++) {string password;getline(cin, password);if (isValidPassword(password)) {cout << "YES" << endl;} else {cout << "NO" << endl;}}return 0;
}
時間復雜度:O(n*m),空間復雜度:O(m)。
我們目前要寫出來C++的寫法是非常考驗前面C++的學習情況,大家可以嘗試去寫一寫,優先掌握C語言的寫法,博主還沒有介紹C++的算法題,之后會涉及的,敬請期待!
結尾
本文內容到這里就全部結束了,希望大家練習一下這幾道題目,這些基礎題最好完全掌握!
往期回顧:
【C語言16天強化訓練】從基礎入門到進階:Day 3
【C語言16天強化訓練】從基礎入門到進階:Day 2
【C語言16天強化訓練】從基礎入門到進階:Day 1
結語:感謝大家的閱讀,記得給博主“一鍵四連”,感謝友友們的支持和鼓勵!