字符串习题

单词个数统计

原作:

输入: 一行字符串。仅有空格和英文字母构成。

输出:

英文字母个数letter_num

单词个数word_num

出现最多的字母max_letter

出现最多的字母的出现次数max_letter_frequ

处理:

  1. 统计并输出此句子英文字母的个数;

  2. 统计并输出此句子中单词的个数;

  3. 查找此句子中出现次数最多的字母(不区分大小写,大小写字母是相同的)及次数。当出现最多的字母不止一个时,全部找到,并输出找到的所有字母及次数。(输出顺序按字母顺序,且输出时字母全部小写)

cpp 复制代码
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.输入语句发生错误:

cpp 复制代码
scanf("%s", arr);

%s 读取遇到空格就结束了,所以无法读入整行句子。句子有空格的话,后面的内容根本读不到。

应改为:

cpp 复制代码
fgets(arr, sizeof(arr), stdin);

2.英文字母个数,单词个数统计错误:

按照上面的写法, 会把非空格的字符都算进去,但题目要求只统计英文字母个数。 即 如果 s[i] 是换行符 \n,也会被统计进去。

正确的改法应该是:

cpp 复制代码
if ( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') ) {
    letter_num++;
}

或者用 isalpha(s[i])。 isalpha() 是标准C库函数,作用是判断字符是否为英文字母(A-Z,a-z)。

对于统计单词个数:你要使用上述的这个语句来统计单词个数,得先去掉开头和结尾的空格。

或者推荐使用下列的做法:

cpp 复制代码
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;
    }
}
复制代码

正确代码

cpp 复制代码
#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++;
            //统一转成小写,再加入myMap
            char 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的岗位都访问完了,还要向前再加一位)

cpp 复制代码
#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.字符串操作

cpp 复制代码
a.find('.');//找到字符串中第一次出现 . 的位置,返回下标。如果找不到,返回 string::npos
a.substr(0, pos)//从下标 0 开始,截取 pos 长度的子串

2.max() 是 C++ 标准库 <algorithm > 中的函数,用来返回两个值中的较大值。

知识点

将大写字母转为小写字母的方式

用tolower() 或者使用ASCII码

tolower() 是 C 标准库 里的函数

cpp 复制代码
#include <cctype>
​
char lower = tolower('A'); // 结果是 'a'
​

在 ASCII 表中:

  • 大写字母 'A''Z' 的值是 65 ~ 90

  • 小写字母 'a''z' 的值是 97 ~ 122

  • 大小写之间的差值是 32

cpp 复制代码
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,也就是竖式加法里的"要进位"条件。

相关推荐
qq_447663051 小时前
《Spring日志整合与注入技术:从入门到精通》
java·开发语言·后端·spring
蜡笔小新星1 小时前
OpenCV中文路径图片读写终极指南(Python实现)
开发语言·人工智能·python·opencv·计算机视觉
Rverdoser1 小时前
java八股文之消息中间件
c#·linq
七七知享1 小时前
2024 Qiniu 跨平台 Qt 高级开发全解析
开发语言·qt·零基础·操作系统·跨平台·qt5·精通
脏脏a1 小时前
C 语言分支与循环:构建程序逻辑的基石
c语言·开发语言
结衣结衣.2 小时前
【Qt】带参数的信号和槽函数
开发语言·qt·c++11
冷琴19962 小时前
基于Python+Vue开发的电影订票管理系统源码+运行步骤
开发语言·vue.js·python
L Jiawen2 小时前
【Python 2D绘图】Matplotlib绘图(统计图表)
开发语言·python·matplotlib
Run_Teenage2 小时前
C语言每日一练——day_4
c语言·开发语言
SongYuLong的博客2 小时前
C# WPF 串口通信
开发语言·c#·wpf