字符串经典题

序号题目难度链接外链
1.仅仅反转字母简单跳转LeetCode
2.第一个唯一的字符简单跳转LeetCode
3.最后一个单词的长度简单跳转LeetCode
4.验证回文串简单跳转LeetCode
5.字符串加法简单跳转LeetCode
6.字符串乘法中等跳转LeetCode
7.字符串转换为整数简单跳转牛客
8.字符串区间反转简单跳转LeetCode
9.反转单词简单跳转LeetCode
10.罗马数字转换为整数简单跳转LeetCode
11.字符串匹配问题(KMP)中等跳转LeetCode
12.外观数列简单跳转LeetCode
13.二进制加法简单跳转LeetCode
14.赎金信简单跳转LeetCode
15.求单词的个数简单跳转LeetCode
16.重复的子字符串中等跳转LeetCode
17.URL化简单跳转LeetCode
18.学生出勤记录I简单跳转LeetCode
19.长按键入简单跳转LeetCode
20.亲密字符串中等跳转LeetCode

LeetCode917:仅仅反转字母

在这里插入图片描述

思路很简单,前后扫描即可

class Solution {
public:
    bool Isalpha(char ch)
    {
        if(ch>='a' && ch<='z')
            return true;
        if(ch>='A' && ch<='Z')
            return true;
        return false;
    }

    string reverseOnlyLetters(string S) 
    {
        size_t begin=0;
        size_t end=S.size()-1;

        while(begin<end)
        {
            if(S.empty())
                return S;
            while(begin<end && !Isalpha(S[begin]))
                begin++;
            while(begin<end && !Isalpha(S[end]))
                end--;

            swap(S[begin],S[end]);
            begin++;
            end--;
        }

        return S;
    }
};

LeetCode387:字符串中第一个唯一字符

在这里插入图片描述

这种题暴力破解会导致时间复杂度非常高,所以可以使用散列表的思想,为每个字母添加一个映射,利用数组,相同字母个数就增加。这里可以以字母a作为基准,这样的话数组下标就可以从0开始了

class Solution {
public:
    int firstUniqChar(string s)
    {
        int cout[26]={0};//26个字母进行映射
        for(int i=0;i<s.size();i++)//相同字母进行统计
        {
            cout[s[i]-'a']++;
        }
         for(int i=0;i<s.size();i++)
        {
           if(cout[s[i]-'a']==1)//第一个出现1次的输出
                return i;
        }
        return -1;
    }
};

牛客:最后一个单词的长度

在这里插入图片描述

这道题思路比较简单,但是要注意一个问题,字符串是以空格分隔的,所以使用cin接受时可能导致空格之后的单词无法接收到,所以要使用getline,他可以接受一行,也就是接受空格

#include <string>
#include <iostream>

using namespace std;
int main()
{
    string s;
    getline(cin,s);
    
    size_t pos=s.rfind(" ");
    if(pos!=string::npos)
    {    
        cout<<s.size()-1-pos<<endl;
    }
    else
    {
        cout<<s.size()<<endl;
    }
    

}

LeetCode125:验证回文串

在这里插入图片描述

此题也是比较简单

class Solution {
public:
    

    bool isPalindrome(string s) 
    {
        for(int i=0;i<s.size();i++)//将所有的小写字母转换为大写字母
        {
            if(s[i]>='a' && s[i]<='z')
            {
                s[i]-=32;
            }
        }

        int begin=0;
        int end=s.size()-1;
        while(begin<end)
        {
            while(begin<end && !isalnum(s[begin]))//不是字母或数字
                begin++;
            while(begin<end && !isalnum(s[end]))
                end--;

            if(s[begin]!=s[end])
            {
                return false;
            }
            else
            {
                begin++;
                end--;

            }


        }
        return true;

    }
};

LeetCode415:大数运算之加法(重要)
在这里插入图片描述
这是一道非常经典的题目,运算时每次单个位相加,同时注意数字和字符之间的转换,然后注意进位。最后字符由于是尾插进去的,所以要反转

class Solution {
public:
    string addStrings(string num1, string num2) 
    {
        string ret;//返回结果字符串
        int end1=num1.size()-1;
        int end2=num2.size()-1;//end1和end2分别用来从后向前扫描num1和num2字符串
        int next=0;//标记进位
        while(end1>=0 || end2>=0)//扫描
        {
            int ret1=0,ret2=0;//用来接受对应单个位置的字符
            if(end1>=0)
            {
                ret1=num1[end1--]-'0';//转换为数字
                
            }
            if(end2>=0)
            {
                ret2=num2[end2--]-'0';//转换为数字
            }
            int retch=ret1+ret2+next;//单位相加注意加进位
            if(retch>=10)//如果大于10表示,下一位要进位
            {
                retch-=10;//留下个位数字
                next=1;
            }
            else
            {
                next=0;//如果不大于10,就不仅为
            }
            ret+=(retch+'0');//转化为字符,并尾插到返回字符数组中
        }
        if(next==1)//有一种特殊情况就是9999+1,所以特殊处理
        {
            ret+='1';
        }

        reverse(ret.begin(),ret.end());//由于是尾插所以注意反转
        return ret;

    }
};

LeetCode43:大数运算之乘法

在这里插入图片描述

解法就是竖式计算,第二行的从后向前每一位去乘第一行的每一位,注意第二行不从倒数第一个开始时要补位

 string multiply(string num1, string num2) 
    {
        if(num1=="0" || num2=="0")//0乘任何数都是0
            return "0";
        
        string ret="0";//返回的字符串
        int n1=num1.size()-1,n2=num2.size()-1;//n1和n2分别扫描num1和num2
        for(int i=n2;i>=0;i--)//扫描num2
        {   
            string curr;//单个位相乘,暂时保存的字符串
            int add=0;//用于进位
            for(int j=n2;j>i;j--)//用于补位
            {
                curr.push_back('0');
            }

            int y=num2[i]-'0';//乘法运算,用num2的这一位去乘num1的每一位
            for(int j=n1;j>=0;j--)//num1的每一位
            {
                int x=num1[j]-'0';//转换为数字
                int retch=x*y+add;//注意加上进位

                curr.push_back((retch%10)+'0');//结果尾插进去字符串
                add=retch/10;//进位值
            }
           
            while(add!=0)//比如9×9=81,这种特殊情况
            {
                curr.push_back(add%10+'0');
                add/=10;
            }
            reverse(curr.begin(),curr.end());//由于是尾插,注意反转

            ret=addStrings(ret,curr);//结果依次进行字符串相加

        }
        return ret;

牛客:字符串转换为整数
在这里插入图片描述

此题也非常简单

class Solution {
public:
    int StrToInt(string str) 
    {
        
        int flag=1;//判断是否为负数
        int begin=0;//起始位置
        int end=str.size()-1;//结束位置
        int sum=0;//返回的数字
        int j=10;//倍加
        if(str[begin]=='-')//处理负号
        {
            flag=-1;
            begin++;
        }
        if(str[begin]=='+')//处理正号
        {
            flag=1;
            begin++;
        }
        while(begin<=end)
        {
            if(str[begin]>='0' && str[begin]<='9')//只有合法才可以转换
            {
                int num=str[begin]-'0';
                sum=sum*j+num;
                begin++;
            }
            else
                return 0;
            
        }
        
        return sum*flag;
        
        
    }
};

LeetCode 541:字符串部分区间反转

在这里插入图片描述

这道题,用for循环每次控制2k个区间,然后每次循环时去判断剩余字符个数是否小于个,如果大于等于k个就反转这个2k区间的前k个,循环结束时,肯定剩余的字符就小于了k个,然后把剩余字符反转

class Solution {
public:
    string reverseStr(string s, int k) 
    {
        for(int i=0;i<s.size();i+=(2*k))
        {
            if(i+k<=s.size())//剩余的字符大于等于k个,但小于2k
            {
                reverse(s.begin()+i,s.begin()+i+k);//反转前k个
                continue;//继续反转,直到

            }
            reverse(s.begin()+i,s.begin()+s.size());//剩余k个

        
        }
     return s;
    }
   
};

LeetCode557:反转字符串中的单词

这里是引用

这道题可以用到上面讲到过过的find_first_of,不断找下一个空格

class Solution {
public:
    string reverseWords(string s) 
    {
        int begin=0;
        int end=s.find_first_of(" ");//先找到第一个空格
        if(end==string::npos)//如果整个字符串没有空格
        {
            reverse(s.begin(),s.end());//翻转整个字符串
        }
        while(end!=string::npos)//不断找空格
        {
  
            reverse(s.begin()+begin,s.begin()+end);//翻转区间
            begin=end+1;//begin向后走
            end=s.find_first_of(" ",begin);//end从下一个位置开始再找空格
            if(end==string::npos)//一旦end=npos时,就无法进入while了,直接把剩余部分翻转
            {
                reverse(s.begin()+begin,s.end());
                break;
            }

        }
        return s;
    }
};

罗马数字转换为整数

这里是引用

此题也是非常简单,扫描字符串,挨个累加即可
处理情况时,举个例子,IV应该被解析为4而不是6,所以在case V中,看一下它前一个字符是不是I,如果是I那么它已经被解析为了6,所以而与实际情况相比,相差2,所以减去2即可。依次类推

class Solution {
public:
    int romanToInt(string s) 
    {
        int num=0;
        for(int i=0;i<s.size();i++)
        {
            switch (s[i])
            {
                case 'I':
                    num+=1;
                    break;
                case 'V':
                    num+=5;
                    if(i>0 && s[i-1]=='I')//特殊处理IV
                        num-=2;
                    break;
                case 'X':
                    num+=10;
                    if(i>0 &&s[i-1]=='I')//特殊处理IX
                        num-=2;
                    break;
                case 'L':
                    num+=50;
                    if(i>0 &&s[i-1]=='X')//特殊处理XL
                        num-=20;
                    break;
                case 'C':
                    num+=100;
                    if(i>0 &&s[i-1]=='X')//特殊处理XC
                        num-=20;  
                    break;
                case 'D':
                    num+=500;
                    if(i>0 &&s[i-1]=='C')//特殊处理CD
                        num-=200;
                    break;
                 case 'M':
                    num+=1000;
                    if(i>0 &&s[i-1]=='C')//特殊处理CM
                        num-=200;
                    break;
                default:
                    break;
            }

        }
        return num;
    }
};

LeetCode28:字符串匹配问题

这里是引用

此题可以用KMP算法求解,KMP算法对于初学者来说可以说是一个劝退算法,本人在这篇博客中对KMP有很详细的讲解,保证你看完就会

KMP算法详细讲解

class Solution {
public:
    void getnext(string& target,int next[])//next数组
    {
        int i=0;
        int k=-1;
        next[0]=-1;
        while(i<target.size()-1)//注意越界问题,
        {
            if(k==-1 || target[i]==target[k])
            {
                i++;
                k++;
                next[i]=k;
            }
            else
            {
                k=next[k];
            }
        }

    }

    int strStr(string haystack, string needle) 
    {
        if(needle=="")//目标串为空,返回0
            return 0;
        if(haystack=="")//主串为空,返回-1
        {
            return -1;
        }
        int* next=new int[needle.size()];//申请next数组
        int i=0;//i和j分别扫描主串和目标串
        int j=0;
        getnext(needle,next);//构建next疏忽组
        int m=haystack.size();//两个字符串的长度
        int n=needle.size();
        while(i<m && j<n)//KMP算法
        {
            if(j==-1|| haystack[i]==needle[j])
            {
                i++;
                j++;
            }
            else
            {
                j=next[j];
            }
        }

        if(j>=needle.size())
            return i-needle.size();//返回目标串的下标
        else
            return -1;//找不到返回-1
    }
};

LeetCode38:外观数列

这里是引用

此题题目较长,但是仔细理解后会发现比较有意思。这个数列每个对象都是对前一个对象的描述,所以它要第几个对象,我就剩生成几个对象,就是两个for循环的迭代操作

class Solution {
public:
    string countAndSay(int n) 
    {

      string arr[n];//给几个n就生成几个对象
      arr[0]="1";//第一个是原始
      for(int i=1;i<n;i++)//每一个对象都要对前一个对象进行描述
      {
          int index=1;//这个表示连续字符的个数
          for(int j=0;j<arr[i-1].size();j++)//用于扫描前一个对象,以此来生成此对象
          {

              char ch=arr[i-1][j];//保存一下字符
              if(j+1<arr[i-1].size() && arr[i-1][j+1]==ch)//如果是连续的那么就多一个数目
              {
                  index++;
              }
              else//直到不是连续的字符,直接进行对象对象
              {
                  arr[i]+=(index+'0');//个数
                  arr[i]+=ch;//字符
                  index=1;//重新置为1
              }
          }
      }
    return arr[n-1];
    }
    

};

LeetCode67 二进制加法

这里是引用

换汤不换药

class Solution {
public:
    string addBinary(string a, string b) 
    {
        string ret;
        int end1=a.size()-1;
        int end2=b.size()-1;
        int next=0;
        while(end1>=0 || end2>=0)
        {
            int ret1=0;
            int ret2=0;
            if(end1>=0)
            {
                ret1=a[end1--]-'0';
            }
            if(end2>=0)
            {
                ret2=b[end2--]-'0';
            }
            int retch=ret1+ret2+next;
            if(retch>1)
            {
                retch-=2;//进位
                next=1;
            }
            else
                next=0;

            ret+=(retch+'0');

        }
        if(next==1)
        {
            ret+='1';
        }

        reverse(ret.begin(),ret.end());
        return ret;
    }
};

这里是引用

这道题其实和“第一个唯一的字符”那个题基本一致,都是进行映射

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine)
    {
        if(ransomNote=="")//如果ransomnote为空,则返回true
            return true;
        if(magazine=="")//如果magazine为空,则返回flase
            return false;

        int* count=new int[26];//开辟存放26个字母的数组
        for(int i=0;i<26;i++)
        {
            count[i]=0;
        } 
        for(int i=0;i<magazine.size();i++)//映射
        {
            count[magazine[i]-'a']++;
        }


        for(int j=0;j<ransomNote.size();j++)//只要有的全部对应减去
        {
            if(count[ransomNote[j]-'a']>0)
            {
                count[ransomNote[j]-'a']--;
            }
            else//一旦小于等于0,肯定不存在
                return false;
        }
        return true;
    }
};

这里是引用

此题非常简单,我写得有点麻烦,不过可读性很强

class Solution {
public:
    int countSegments(string s) 
    {
        if(s=="")//如果是空字符返回0
            return 0;

        int num=0;//记录字符总数
        int start=0;//判断非空格
        int non_sapace=0;//消除空格
        int end=s.size()-1;
        while(s[end]==' ')//消除后面的空格,直到最后一个单词末尾
        {
            if(end==start && s[end]==' ')//如果end=start并且这个字符还是空那么就是0
                return 0;
            end--;
        }
        
        while(start<=end && non_sapace<=end)//扫描
        {
            while(s[non_sapace]==' ')//先用nonspace消除空格
                non_sapace++;
            start=non_sapace;//找到某个单词的第一个位置

            while(start<=end && s[start]!=' ')//扫描完整个单词
            {
                start++;
            }
            num++;//表示单词+1
            non_sapace=start;//循环,用non——space消除空格
        }
        return num;
    }
};

LeetCode459:重复的子字符串

在这里插入图片描述
这道题有必要好好说明一下

我们把字符串s中循环的子字符串称为循环节,题目就是要让我们判断一个字符串有没有循环节

如果没有循环节,我们两个字符串拼接到一起,称为ss,那么ss中肯定有两个s,那么从ss中寻找s,必然能找到,并且返回值一定是s.size()
在这里插入图片描述
如果有循环节,那么设循环节的长度为len,那么ss中必然有ss.size()/len+1个循环节,然后“去掉ss中的第一个字符”,也就是从ss的第二个位置开始寻找s,那么既然有循环节,所以如果其返回值不是s.size()的话那么就能证明成功
在这里插入图片描述
所以直接可以用一行代码解决

class Solution {
public:
    bool repeatedSubstringPattern(string s) 
    {
        return (s+s).find(s,1)!=s.size();
    }
};

LeetCode01.03:URL化

这里是引用

这道题和剑指offer的面试题5:替换空格基本相似,但是这道题中给出的是真实的字符串的长度,这一点是需要十分注意的

    string replaceSpaces(string S, int length) 
    {
        int length_bak=length;
        int i=0;
        int real_space=0;;
        while(length_bak--)//统计有效的空格
        {
            if(S[i]==' ')
                real_space++;
            i++;
        }

    string ret;
    ret.resize(length+2*real_space+1);//多申请一个空格存放'\0'
    
    int j=length-1;
    int k=ret.size()-2;//这里-2
   
    while(k>=0)
    {
        if(S[j]!=' ')
        {
            ret[k--]=S[j--];
        }
        else
        {
            ret[k--]='0';
            ret[k--]='2';
            ret[k--]='%';
            j--;
        }
    }

    return ret;
    }

LeetCode551:学生出勤记录I

这里是引用

此题较为简单。注意我们判断时,只需判断LLL是否是S的字符串,如果是那肯定false,如果不是就表明s中不可能存在LLL,LLLLL这样的字符串,最多也只能是LL

class Solution {
public:
    bool checkRecord(string s) 
    {
        int A_number=0;
        if(strstr(s.c_str(),"LLL")!=NULL)
        {
            return false;
        }
        else
        {
            for(int i=0;i<s.size();i++)
            {
                if(s[i]=='A')
                    ++A_number;
                if(A_number>1)
                    return false;
            }
        }
        return true;
    }
};

LeetCode925:长按键入

在这里插入图片描述

这道题解决时使用for循环去遍历typed,然后如果对应相同就同步扫描,然后如果不对应相同,那么就看一下此处typed[j]和name[i-1]是否相同,如果相同那么说明typed[j]就是被长按出来的

class Solution {
public:
    bool isLongPressedName(string name, string typed) 
    {
        int i=0;
        int j=0;
        for(j=0;j<typed.size();j++)
        {
            if(name[i]==typed[j])//对应相等,同步扫描
                i++;
            else if(i-1>=0 && typed[j]==name[i-1])//如果不对应相等,看下typed[j]是否是被长按的
            {
                continue;
            }
            else//除此之外全部是flase
                return false;

        }
        if(i>name.size()-1)//防止name长,typede短的情况发生
            return true;
        else
            return false;
    }
};

LeetCode 859:亲密字符串

这里是引用

这道题需要考虑情况较多。观察其特点,如果是亲密字符串,最多有两个字符位置不同

class Solution {
public:
    bool buddyStrings(string a, string b) 
    {
        if(a.size()!=b.size())//如果长度不相同,肯定false
            return false;
        string differ_a;
        string differ_b;//分别用两个字符串记录a和b不同的字母
        int count=0;//用来记录有几个不同的字母
        for(int i=0;i<a.size();i++)
        {
            if(a[i]!=b[i])//如果不相同
            {
                differ_a+=a[i];
                differ_b+=b[i];//就把对应的字母依次放在两个字符数组中
                count+=1;//说明不相同的字符读多一个
            }
            if(count>2)//一旦出现两个以上不同的字符,那么肯定不是亲密字符串
                return false;
        }
        if(count==2 && differ_a[0]==differ_b[1] && differ_a[1]==differ_b[0])//然后如果是两个字符不同,再看数组a[0]是否等于b[1],a[1]是否等于b[0]
            return true;


        if(count==0)//如果count等于0,说明两个字符串相同,然后在这里,aa和aa返回的是true,ab和ab却返回的是false,    
        //所以就看一下a字符串里里面是否会有相同的字符,如果有那么就能交换因此是亲密。比如说abab和abab
        {
            int arr[26]={0};//根据字母映射关系进行
            for(int i=0;i<a.size();i++)
            {
               if(arr[a[i]-'a']==1)
                    return true;
              arr[a[i]-'a']=1;
            }
            return false;
        }
        return false;
        
    }
};
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐江湖

创作不易,感谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值