• 【c++5道练习题】①


    目录

    一、有限制的累加

    二、计算日期到天数转换

    三、仅仅反转字母

    四、 字符串的第一个唯一字符

    五、字符串最后一个单词的长度


    一、有限制的累加

     题述:

    求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)

     题中已给: 

    1. class Solution
    2. {
    3. public:
    4. int Sum_Solution(int n){
    5. }
    6. };

    知识点考察:

    类的构造函数+ static修饰

    先给代码再说思路:

    代码如下:

    1. #include
    2. using namespace std;
    3. class Sum
    4. {
    5. public:
    6. Sum()//构造函数
    7. {
    8. _sum += _i;
    9. ++_i;
    10. }
    11. static void Init()
    12. {//静态成员函数可以访问静态成员变量
    13. _i = 1;
    14. _sum = 0;
    15. }
    16. static int GetSum()//静态成员函数可访问静态成员变量
    17. {
    18. return _sum;
    19. }
    20. private:
    21. static int _i;//静态成员变量类内声明
    22. static int _sum;
    23. };
    24. int Sum::_i = 1;//静态成员变量类外定义(定义的同时初始化)
    25. int Sum::_sum = 0;
    26. class Solution
    27. {
    28. public:
    29. int Sum_Solution(int n)
    30. {
    31. Sum::Init();//每调用一次Sum_Solution函数都要初始化一次,不然会一直累加
    32. Sum* p = new Sum[n];//创建的同时,会调用n次构造函数
    33. //Sum a[n];//c99下才支持的变长数组
    34. return Sum::GetSum();//静态成员函数可通过类名直接访问
    35. }
    36. };
    37. int main()
    38. {
    39. Solution st;//实例化一个对象
    40. cout << st.Sum_Solution(5) << endl;//累加
    41. cout << st.Sum_Solution(5) << endl;
    42. system("pause");
    43. return 0;
    44. }

    思路:

    自定义类型都要调用构造函数初始化,比如Date a[10] -》10个对象就要调用10次构造函数

    那么n个对象就会调用n次构造函数,就像一个变相的循环

    问题: 

    为什么要用GetSum函数?

    因为成员变量_i和_sum都是private权限下的,故在类外无法直接访问,所以用GetSum进行返回

    为什么要用static修饰?

    因为static是属于类的,每个对象都可以修改静态变量,那就可以实现一个累加效果,那用全局变量不可以吗,当然可用,但是c++中不推荐用全局变量,因为c++强调封装的意义,如果是全局变量谁都可以修改了。

    成员函数用static修饰是因为

    ①、static成员函数才可访问成员变量

    ②、静态成员函数可通过类名加::的方式直接访问

    成员变量用static修饰是因为

    ①、所有对象调用时都会对同一个static变量上运算

    要特别注意一个问题:

    求一次累加和,都要初始化一次,因为OJ上有多个测试用例,需要多次测试的,你在自己编译器下可能就运行一次就跑出来了,但OJ上还是不通过,对于本题,这可能就因为连续累加,每调用一次Sum_Solution函数都在之前基础上累加,为了避免这个问题,我们再每一次调用Sum_Solution函数时都初始化一次(Init函数)。

    二、计算日期到天数转换

    题述:

    根据输入的日期(某年某月某日),计算是这一年的第几天。

    输入描述:

    输入三行,分别是年、月、日

    输出描述:

    返回计算后的第几天

    输入:

    2012

    12

    31

    输出:

    366

    思路:

    ①、创建一个日期类,并写一个运算符相减的重载,用这个日期减去本年的1月1号即可,但是对于这道题复杂化

    ②、从1月累加到本月的前一月,计算天数,时间复杂度:O(1),这个方法简单,本题采用此方法  

    代码如下:

    1. #include
    2. using namespace std;
    3. int main()
    4. {
    5. static int monthDays[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
    6. int year, month, day;
    7. //这样可不断接收输入,直到按ctrl+z就结束
    8. while (cin >> year >> month >> day)
    9. {
    10. int n = 0;
    11. //从1月累加到month的前一月的天数
    12. for (int i = 1; i < month; i++)
    13. {
    14. n += monthDays[i];
    15. }
    16. n += day;
    17. //如果是闰年,且>2月的前提下
    18. if (month > 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
    19. n += 1;
    20. cout << n << endl;
    21. }
    22. return 0;
    23. }

    注意:

    一定要加个while,因为OJ上有多个测试用例,不加while的话一个测试用例是能过,但是OJ上会连续输入,那OJ上也要手动按Ctrl+z结束吗?不是,是OJ把测试用例写入文件中了,然后运行时读文件,读完给后台发个信号就完成了。

    三、仅仅反转字母

    题述:给定一个字符串 s ,返回“反转后的”字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转。

    示例1:

    输入:“ab-cd”

    输出:“dc-ba”

    示例2:

    输入:“a-bc-dEf-ghIj”

    输出:“j-Ih-jfE-dcba”

    题中已给:

    1. class Solution{
    2. public:
    3. string reverseOnlyLetters(string s) {
    4. }
    5. };

    思路:

    遍历方法用下标访问方便,不采用迭代器遍历字符串。

    本质思路类似于快速排序实现的单趟排序的左右指针法

    仅仅交换字母,那就定义两个下标begin=0,end=字符串大小-1begin从左向右走,end从右向左走,两者直到找到对应的值为字母才会停下并交换,那整个大前提就是begin才会继续,在begin和end找的过程中也要要求begin

    1. class Solution{
    2. public:
    3. //判断一个字符是不是字母
    4. bool Ischar(char ch)
    5. {
    6. if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
    7. {
    8. return true;
    9. }
    10. else
    11. {
    12. return false;
    13. }
    14. }
    15. //仅仅交换字母
    16. string reverseOnlyLetters(string s) {
    17. int begin = 0;
    18. int end = s.size() - 1;//算出s的大小,求出最后一个数的下标
    19. while (begin < end)//大前提是begin < end循环才继续
    20. {
    21. while (begin < end && Ischar(s[begin]) == false)
    22. {//在走的过程中begin < end才能继续往下走,直到找到s[begin]是字母为止
    23. begin++;
    24. }
    25. while (begin < end && Ischar(s[end]) == false)
    26. {//在走的过程中begin < end才能继续往下走,直到找到s[end]是字母为止
    27. end--;
    28. }
    29. swap(s[begin], s[end]);//c++自动提供swap交换函数
    30. //交换完后begin还要++,end还要--
    31. begin++;
    32. end--;
    33. }
    34. return s;//返回字符串
    35. }
    36. };

    四、 字符串的第一个唯一字符

    题述:

    给定一个字符串,找到他的第一个不重复的字符,并返回它的索引。若不存在,则返回-1.

    案例:

    s = "leetcode"

    返回 0

    s = "loveleetcode"

    返回 2

    要求:

    时间复杂度:O(N)

    空间复杂度:O(1)

    注意事项:

    您可假定该字符串只包含小写字母

    题中已给:

    1. class Solution {
    2. public:
    3. int firstUniqChar(string s) {
    4. }
    5. };

    思路:

    利用计数排序的思路,计数排序本质就是哈希,若用暴力求解法时间复杂度:O(N*N)

    和计数排序思路一样,不会计数排序就看我写的八大排序的文章

    1. class Solution {
    2. public:
    3. int firstUniqChar(string s) {
    4. //使用映射的方式统计次数
    5. int count[26] = { 0 };//26个小写字母
    6. for (auto ch : s)
    7. {//范围for遍历s
    8. count[ch - 'a']++;//'a'-'a'就变为0
    9. }
    10. for (size_t i = 0; i < s.size(); ++i)
    11. {
    12. if (count[s[i] - 'a'] == 1)
    13. return i;//出现一次则返回对应索引
    14. }
    15. return -1;//没有出现一次的则返回-1
    16. }
    17. };

    五、字符串最后一个单词的长度

    题述:

    计算字符串最后一个单词的长度,单词以空格隔开

    输入描述:

    一行字符串,非空,长度<5000

    输出描述:

    整数N,最后一个单词的长度

    输入:

    hello world

    输出:

    5

    思路:

    因为每个单词都以空格分隔,求长度简单,但怎么找最后一个单词,找最后一个空格即可,那就可用到rfind(),若找到对应字符返回其下标,若没找到返回-1,它会从后往前找,找到第一次的即可。

    一个单词也没有空格怎么办?rfind()没找到会返回-1,而代码中s.size() - 1 - pos,pos=-1,相当于直接求出长度,所以无需格外考虑 

    典型的错误代码:

    1. #include
    2. using namespace std;
    3. int main()
    4. {
    5. string s;
    6. cin >> s;//输入字符串
    7. //从字符串后面往前找第一次出现的' ',并返回其下标给pos
    8. size_t pos = s.rfind(' ');
    9. //利用下标计算最后一个单词的长度
    10. cout << s.size() - 1 - pos << endl;
    11. return 0;
    12. }

     注意: 

     当输入的有空格、制表符、换行符时cin就不读了和scanf一样,但本题以空格为分隔,故用getline才行,getline只有遇到换行才结束

    getline的使用说明如下:

     正确代码:

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. string s;
    7. //cin >> s;//遇到空格、制表符、换行就结束了
    8. getline(cin, s);//遇到换行才结束
    9. //从字符串后面往前找第一次出现的' ',并返回其下标给pos
    10. size_t pos = s.rfind(' ');
    11. //利用下标计算最后一个单词的长度
    12. cout << s.size() - 1 - pos << endl;
    13. return 0;
    14. }

  • 相关阅读:
    项目问题-Invalid bound statement (not found),mybatis出现的问题
    网球场地预约
    Vue - Syntax Error: TypeError: this.getOptions is not a function 项目运行时报错,详细解决方案
    dubbo 自定义异常
    Java Tomcat内存马——Servlet内存马
    luma.oled 常用函数
    0.Flask入门
    【LeetCode】Day148-目标和
    【操作系统】6/35子进程
    ssm生鲜超市管理系统的设计与实现毕业设计源码261635
  • 原文地址:https://blog.csdn.net/m0_74044018/article/details/132015260