C++学习笔记(十二)——String类练习题(下)

简介: C++学习笔记(十二)——String类练习题(下)

仅仅反转字母


image.png

双指针

我们使用 left 指针从左边开始扫描字符串s, right指针从右边开始扫描字符串 s。如果两个指针都扫描到字母,且 left<right,那么交换 s[left] 和 s[right],然后继续进行扫描;否则表明反转过程结束,返回处理后的字符串。

class Solution {
public:
    bool letter(char ch)
    {
        if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
        {
            return true;
        }
        else{
            return false;
        }
    }
    string reverseOnlyLetters(string s) {
    int begin=0;
    int end=s.size()-1;
     while(begin<end)
     {
      while(begin<end&&!letter(s[begin]))
      {
         ++begin;
      }
      while(begin<end&&!letter(s[end]))
      {
          --end;
      }
      swap(s[begin],s[end]);
      ++begin;
      --end;
     }
     return s;
    }
};

哈希表

class Solution {
public:
    string reverseOnlyLetters(string s) {
     map<int,char> no;
     int len=s.size()-1;
     string m;
     for(int i=len;i>=0;i--)
     {
         if(isalpha(s[i]))
         {
            m+=s[i];
         }
         else{
            no[i]=s[i];
         }
     }
     for(auto it=no.begin();it!=no.end();it++)
     {
         m.insert(it->first,1,it->second);
     }
     return m;
    }
};

用栈处理

class Solution {
public:
   //栈
    string reverseOnlyLetters(string s) {
      stack<char> a;
      int len=s.size()-1;
      string m;
      for(int i=0;i<=len;i++)
      {
          if(isalpha(s[i]))
          {
             a.push(s[i]);
          }
      }
      for(int i=0;i<=len;i++)
      {
          char ch;
         if(isalpha(s[i]))
         {
          ch=a.top();
          a.pop();
         }
         else{
             ch=s[i];
         }
         m+=ch;
      }
      return m;
    }
};

字符串中的第一个唯一字符


image.png

数组下标

class Solution {
public:
    int firstUniqChar(string s) {
    int count[26]={0};
    int len=s.size()-1;
    for(int i=0;i<=len;i++)
    {
        count[s[i]-'a']++;
    }
    for(int i=0;i<=len;i++)
    {
        if(count[s[i]-'a']==1)
        {
            return i;
        }
    }
    return -1;
    }
};

哈希表 

class Solution {
public:
    int firstUniqChar(string s) {
     unordered_map<char,int> a;
     int len=s.size()-1;
     for(int i=0;i<=len;i++)
     {
         a[s[i]]++;
     }
     for(int i=0;i<=len;i++)
     {
         if(a[s[i]]==1)
         {
             return i;
         }
     }
     return -1;
    }
};

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


image.png

#include<iostream>
using namespace std;
int  main()
{
   string s;
  while(getline(cin,s))
  {
      int pos=s.rfind(' ');
      cout<<s.size()-1-pos<<endl;
  }
    return 0;
}

验证回文串


image.png

class Solution {
public:
    bool isletter(char ch)
    {
       //判断是否是字母或者是数字
        if((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
        {
            return true;
        }
        else{
            return false;
        }
    }
    bool isPalindrome(string s) {
       //先把大写字母转换成小写字母
        for(auto& ch:s)
        {
            if(ch>='a'&&ch<='z')
            {
                ch-=32;
            }
        }
      int begin=0,end=s.size()-1;
      while(begin<end)
      {
       //判断是否是字母或者是数字,不是就一直走
          while(begin<end&&!isletter(s[begin]))
          {
              ++begin;
          }
          while(begin<end&&!isletter(s[end]))
          {
              --end;
          }
      //当到这里,说明这两个数是字母或者数字,判断是否相等
          if(s[begin]!=s[end])
          {
              return false;
          }
       //如果相等继续移动指针比较后面的,如果不相等,上一步直接返回false
          else{
              ++begin;
              --end;
          }
      }
      return true;
    }
};

字符串相加


df84e23ad1ac412b880ce915be7e1e21.png

class Solution {
public:
   //大数相加
   //从后往前加+=,以后再用reverse反转过来
   // 123
  // + 48
    string addStrings(string num1, string num2) {
     int end1=num1.size()-1;
     int end2=num2.size()-1;
     int value1=0,value2=0,next=0;
     int  addret=0;
     string sum;
     while(end1>=0||end2>=0)
     {
         if(end1>=0)
         {
          value1=num1[end1--]-'0';
         }
         else{
             value1=0;
         }
         if(end2>=0)
         {
             value2=num2[end2--]-'0';
         }
         else{
             value2=0;
         }
         addret=value1+value2+next;
         if(addret>9)
         {
             next=1;
             addret-=10;
         }
         else{
             next=0;
         }
         sum+=(addret+'0');
     }
     if(next==1)
     {
         sum+='1';
     }
       reverse(sum.begin(),sum.end());
        return sum;
    }
};

反转字符串||


image.png

我们直接按题意进行模拟:反转每个下标从 2k2k 的倍数开始的,长度为 kk 的子串。若该子串长度不足 kk,则反转整个子串。

class Solution {
public:
    string reverseStr(string s, int k) {
        int n = s.length();
        for (int i = 0; i < n; i += 2 * k) {
            reverse(s.begin() + i, s.begin() + min(i + k, n));
        }
        return s;
    }
};

反转字符串中的单词|||


image.png

class Solution {
public:
    string reverseWords(string s) {
        if(s.size()==1||s.size()==0) return s;  //如果s的长度为0或者1就没必要有后续了;
        int i = 0, j = 0;     //定义“双指针”吧,i后面用来指向单词end(),j用来指向单词第一个;
        for(auto ch:s){
            if(ch==' '){
           reverse(&s[j],&s[i]);   //翻转单词
           j=i+1;      //反复指向单词首个字符
            }
            ++i;
        }
if(s[s.size()-1]!=' ')     //如果最后一个单词最后字符不是空格,那还得翻转一次
        reverse(&s[j],&s[i]);
      return s;
    }
};

字符串相乘


image.png

在相乘或者相加计算过程的每一位,我们可以考虑先不去满10进位,等到计算完所有的相乘结果以后,最终将其加到一块,再去满10进位 ,最后的结果和普通竖式 一样,但却可以大大简化我们的模拟过程。(如下图所示)

32e29166e78ea9f08ed350bd84b746e6.png

1、长度是n和长度是m的数字相乘,最多只有n + m位,为了方便计算,将num1和num2反向存储到A[]和B[]中,即位数低的在数组前面,且开一个大小是n + m的C[]存储计算后的答案。

2、两个数相乘时,将A[i] * B[j]的结果累加到C[i + j]中,最后C[i + j]表示i + j这个位数的值是C[i + j](如上图所示)

3、由于C[]数组中的某些位数字可能是大于等于10的,我们从0枚举到n + m - 1,进行满10进位, 将所有位的值全部变成个位数。

4、最后将C[]数组反转输出。

class Solution {
public:
    string multiply(string num1, string num2) {
        vector<int> A, B;
        int n = num1.size(), m = num2.size();
        for (int i = n - 1; i >= 0; i -- ) A.push_back(num1[i] - '0'); //反向存贮
        for (int i = m - 1; i >= 0; i -- ) B.push_back(num2[i] - '0');
        vector<int> C(n + m);
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                C[i + j] += A[i] * B[j];
        int t = 0;  //存贮进位
        for (int i = 0; i < C.size(); i ++ ) {
            t += C[i];
            C[i] = t % 10;
            t /= 10;
        }
        int k = C.size() - 1;
        while (k > 0 && !C[k]) k -- ;  //去除前导0
        string res;
        while (k >= 0) res += C[k -- ] + '0';  //反转
        return res;
    }
};

找出字符串中第一个只出现一次的字符


image.png

这一题和上面一题极为相似,那题我用了数组下标做的,这题当然也是可以,不过换个思路做,拓展下知识面.

#include<iostream>
using namespace std;
int main()
{
    string s;
    while(getline(cin,s))
    {
        for(int i=0;i<s.size();i++)
        {
            if(s.find_first_of(s[i])==s.find_last_of(s[i]))//从前往后找,从后往前找,如果是同 
       一个数那说明这个是第一个只出现了一次,返回该字母
            {
                cout<<s[i]<<endl;
                break;
            }
//如果走到最后还没有找到,说明没有,返回-1
            if(i==s.size()-1)
            {
                cout<<-1<<endl;
              }
        }
    }
    return 0;
}


相关文章
|
2月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
321 5
|
6月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
191 0
|
6月前
|
存储 编译器 C语言
关于string的‘\0‘与string,vector构造特点,反迭代器与迭代器类等的讨论
你真的了解string的'\0'么?你知道创建一个string a("abcddddddddddddddddddddddddd", 16);这样的string对象要创建多少个对象么?你知道string与vector进行扩容时进行了怎么的操作么?你知道怎么求Vector 最大 最小值 索引 位置么?
178 0
|
6月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
291 0
|
8月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
345 12
|
9月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
9月前
|
存储 编译器 C++
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。
|
9月前
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!
|
10月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
9月前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
192 16