單詞個數統計
原作:
輸入: 一行字符串。僅有空格和英文字母構成。
輸出:
英文字母個數letter_num
單詞個數word_num
出現最多的字母max_letter
出現最多的字母的出現次數max_letter_frequ
處理:
-
統計并輸出此句子英文字母的個數;
-
統計并輸出此句子中單詞的個數;
-
查找此句子中出現次數最多的字母(不區分大小寫,大小寫字母是相同的)及次數。當出現最多的字母不止一個時,全部找到,并輸出找到的所有字母及次數。(輸出順序按字母順序,且輸出時字母全部小寫)
int main() {//輸入:一行字符串。僅有空格和英文字母構成。 char arr[1024];string s;fgets(arr, sizeof(arr), stdin);s = arr;//英文字母個數int letter_num = 0;//單詞的個數int word_num = 0;map<char,int> myMap;//處理//統計并輸出此句子英文字母的個數for (int i = 0; i < s.size(); i++) {if (s[i] != ' ') {letter_num++;//將s[i]統一轉成小寫if (s[i] >= 'A' && s[i] <= 'Z') {s[i] += 32;}myMap[s[i]]++;if (s[i] == ' ' && s[i + 1] != ' ') {word_num++;}}}//輸出:英文字母的個數printf("%d\n", letter_num);//輸出:單詞的個數printf("%d\n", word_num);//輸出:出現次數最多的字母map<char,int>::iterator it;
?//找到字母出現的最多次數int max = 0;for (it=myMap.begin(); it != myMap.end(); it++) {if (it->second > max) {max = it->second;}}//找到值為max的所有鍵vector<char>max_letters;for (it = myMap.begin(); it != myMap.end(); it++) {if (it->second == max) {max_letters.push_back(it->first);}}//打印輸出max_letters數組中的值for (int i = 0; i < max_letters.size(); i++) {printf("%d ", max_letters[i]);}printf("\n");return 0;
}
代碼分析
上述代碼存在幾處的錯誤,我們來解釋一下:
1.輸入語句發生錯誤:
scanf("%s", arr);
%s
讀取遇到空格就結束了,所以無法讀入整行句子。句子有空格的話,后面的內容根本讀不到。
應改為:
fgets(arr, sizeof(arr), stdin);
2.英文字母個數,單詞個數統計錯誤:
按照上面的寫法, 會把非空格的字符都算進去,但題目要求只統計英文字母個數。 即 如果 s[i]
是換行符 \n
,也會被統計進去。
正確的改法應該是:
if ( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') ) {letter_num++;
}
或者用 isalpha(s[i])
。 isalpha() 是標準C庫函數,作用是判斷字符是否為英文字母(A-Z,a-z)。
對于統計單詞個數:你要使用上述的這個語句來統計單詞個數,得先去掉開頭和結尾的空格。
或者推薦使用下列的做法:
bool in_word = false;
for (int i = 0; i < s.size(); i++) {if (isalpha(s[i])) {if (!in_word) {word_num++;in_word = true;}} else if (s[i] == ' ') {in_word = false;}
}
?
正確代碼
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include <stdio.h>
#include<string>
#include<vector>
#include<map>
?
using namespace std;
?
int main() {//輸入:一行字符串。僅有空格和英文字母構成。 char arr[1024];string s;fgets(arr, sizeof(arr), stdin);s = arr;//英文字母個數int letter_num = 0;//單詞的個數int word_num = 0;map<char,int> myMap;//處理//統計并輸出此句子英文字母,單詞的個數bool in_word = false;//標記是否在單詞中for (int i = 0; i < s.size(); i++) {if (isalpha(s[i])) {letter_num++;//統一轉成小寫,再加入myMapchar ch = tolower(s[i]);myMap[ch]++;//再統計單詞if (!in_word) {word_num++;in_word = true;}}else if (s[i] == ' ') {in_word = false;//遇到空格說明單詞結束}}//輸出:英文字母的個數printf("%d\n", letter_num);//輸出:單詞的個數printf("%d\n", word_num);//輸出:出現次數最多的字母map<char,int>::iterator it;
?//找到字母出現的最多次數int max = 0;for (it=myMap.begin(); it != myMap.end(); it++) {if (it->second > max) {max = it->second;}}//找到值為max的所有鍵vector<char>max_letters;for (it = myMap.begin(); it != myMap.end(); it++) {if (it->second == max) {max_letters.push_back(it->first);}}//打印輸出max_letters數組中的值for (int i = 0; i < max_letters.size(); i++) {printf("%c ", max_letters[i]);}printf("\n");//打印輸出出現最多的字母的出現次數printf("%d\n", max);return 0;
}
浮點數加法
原作:
輸入:有2行,分別表示兩個加數num1 num2
輸出: 一個小數部分不為0的浮點數
處理: 求2個浮點數相加的和
思路:
我們要運算的數已經超過了浮點數精度,稱此類問題為高精度計算。
此題給的兩個數都超過了float和double的精度,所以我們可以把他們表示為兩個字符串,進行運算。
我們要做的實際上就是用字符串模擬小學時學的豎式計算。
1)對齊:把小數點的位置對齊
2)先計算右邊的小數,即進行小數運算
3)再進行左邊的整數,即進行整數運算
對于運算的過程:從右往左算,且計算的是a+b+進位(carry)%10
對于整數的運算,因為兩個加數的位數可能不一樣,所以我們要實現i,j分別指向兩個加數,我們運算的結束條件是,a沒訪問完或者b沒訪問完或者carry==1(即可能存在兩個都訪問完了,但還有進位的情況,例如11+99,在11和99的崗位都訪問完了,還要向前再加一位)
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include <stdio.h>
#include<string>
using namespace std;
/*
參數:一個字符串a
返回值:a的整數部分
處理:提取a的整數部分
*/
string GetInteger(string a) {return a.substr(0, a.find('.'));
}
//提取a的小數部分
string GetFraction(string a) {return a.substr(a.find('.') + 1);
}
?
/*
處理:獲取小數計算的結果,已經最終的進位
因為返回值只能返回一個,我們要兩個結果,故我們都使用引用進行傳遞。
*/
void FractionPlus(string& res, int& carry, string fa, string fb) {
?int size = max(fa.size(), fb.size());while (fa.size() < fb.size()) {fa.push_back('0');}while (fb.size() < fa.size()) {fb.push_back('0');}//開始運算res.resize(size);//給res申請內存空間carry = 0;for (int i = size - 1; i >= 0; i--) {//'0'='0'//'3'='0'+'3'if (fa[i] + fb[i] + carry - '0' > '9') {res[i] = fa[i] + fb[i] +carry- '0' - 10;carry = 1;}else {res[i] = fa[i] + fb[i] + carry - '0';carry = 0;}}return;
}
/*
進行整數運算,整數加法運算不需要修改進位值,只需要獲取小數運算得到的
進位值
*/
void IntegerPlus(string& res, int carry, string ia,string ib) {res.clear();for (int i = ia.size() - 1, j = ib.size() - 1; i >= 0 || j >= 0 || carry == 1; --i, --j) {//a,b都還沒訪問完if (i >= 0 && j >= 0) {if (ia[i] + ib[j] + carry - '0' > '9') {//結果要插入到上一個結果的前面res.insert(res.begin(), ia[i] + ib[j] + carry - '0' - 10);carry = 1;}else {res.insert(res.begin(), ia[i] + ib[j] + carry - '0');carry = 0;}//只有a的情況 ? ? ? ? ? }else if (i >= 0 &&j < 0) {if (ia[i] + carry > '9') {//結果要插入到上一個結果的前面res.insert(res.begin(), ia[i] + carry - 10);carry = 1;}else {res.insert(res.begin(), ia[i] + carry);carry = 0;}}else if (i < 0 && j >= 0) {//只有b的情況 if (ib[j] + carry > '9') {//結果要插入到上一個結果的前面res.insert(res.begin(), ib[j] + carry - 10);carry = 1;}else {res.insert(res.begin(), ib[j] + carry);carry = 0;}}else { //只有進位res.insert(res.begin(), '1');carry = 0;}}}
?
?
int main() {string a;string b;char arr1[1024];char arr2[1024];while (scanf("%s%s", arr1, arr2) != EOF) {a = arr1;b = arr2;string ia = GetInteger(a);string ib = GetInteger(b);string fa = GetFraction(a);string fb = GetFraction(b);string fres;int carry;FractionPlus(fres, carry, fa, fb);string ires;IntegerPlus(ires, carry, ia, ib);string result = ires + '.' + fres;printf("%s\n", result.c_str());}return 0;
}
代碼分析
以上代碼有一些語法值得我們再次復習。
1.字符串操作
a.find('.');//找到字符串中第一次出現 . 的位置,返回下標。如果找不到,返回 string::npos
a.substr(0, pos)//從下標 0 開始,截取 pos 長度的子串
2.max() 是 C++ 標準庫 <algorithm > 中的函數,用來返回兩個值中的較大值。
知識點
將大寫字母轉為小寫字母的方式
用tolower() 或者使用ASCII碼
tolower()
是 C 標準庫 里的函數
#include <cctype>
?
char lower = tolower('A'); // 結果是 'a'
?
在 ASCII 表中:
-
大寫字母
'A'
到'Z'
的值是65 ~ 90
-
小寫字母
'a'
到'z'
的值是97 ~ 122
-
大小寫之間的差值是 32
if (ch >= 'A' && ch <= 'Z') {ch += 32;
}
字符形式進行十進制運算的原理
現在我們想以字符形式進行十進制運算。
字符 '0'
~ '9'
在 ASCII 表中對應十進制數值 48~57。故 '3' + '6' = 51 + 54 = 105;在十進制運算中3 + 6 = 9;顯然,9的ASCII碼不是105,故我們不能簡單的將兩個字符相加來實現。那該怎么辦?
==》因為字符和十進制數字的關系有字符 - '0' = 對應的十進制數字
如果你要對兩個字符表示的數字相加(模擬豎式加法),你需要先把它們轉換成數字再相加:
('3' - '0') + ('6' - '0') = 3 + 6 = 9
在上面的案例中,你可以看作 fa[i] - '0' 得到數字,fb[i] - '0' 得到數字,
然后數字相加,最后 + '0' 變回字符存進 res[i]
所以我們可以直接合并表示為fa[i] + fb[i] + carry - '0'
另外為什么可以與'9'表示,因為fa[i] + fb[i] + carry - '0' 這個結果是字符形式的,而在字符表示下:最大個位數字是 '9'(ASCII 57),如果 這個結果大于'9',也就對應了數字運算中的結果大于9,也就是豎式加法里的“要進位”條件。