string刷题(1~4)

目录

 反转字母

唯一字符 

最后一个单词 

字符串相加 


 反转字母

学习了string后,这道题用c++就会变得很容易解决。

我们可以利用双指针的方式遍历string

记录首尾指针 

 size_t begin = 0,end = s.size()-1;

外循环,保证begin<end

 while(begin<end)
         {  }

然后进入内部后,分别有两个循环,begin和end分别向中间遍历,根据题目要求,交换字母,非字母不管,与使我们得写个判断是否为有效字母的函数,在遍历过程中,发生了位置的相对变化,所以仍然需要判断begin是否小于end。

完善代码:

 bool isValid(char ch)
    {
        if(ch>='a'&&ch<='z')
        {
            return true;
        }
        if(ch>='A'&&ch<='Z')
        {
            return true;
        }
        return false;
    }
   while(begin<end && !isValid(s[begin]))
             {
                 ++begin;
             }
           while(begin<end && !isValid(s[end]))
             {
                 --end;
             }  

接下来进行交换两个字母,用到类交换模板swap函数(不是string::swap)注意完成交换后需要更新begin和end的值

下面是完整代码:

class Solution {
public:
    bool isValid(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,end = s.size()-1;
         while(begin<end)
         {
             while(begin<end && !isValid(s[begin]))
             {
                 ++begin;
             }
           while(begin<end && !isValid(s[end]))
             {
                 --end;
             }  
             swap(s[begin],s[end]);
             ++begin;
             --end;
         }
         return s;
    }
};

唯一字符 

索引:数组下标

这里题目的s只有26个小写字母,所以无需判断合法

这里我们用哈希思想建立26个字母的映射关系

 int count[26] = {0};
        for(auto ch : s)
        {
            count[ch - 'a']++;
        }

接着我们只需返回对应的数组下标就可以啦

完整代码:

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

最后一个单词 

因为字符串末尾不以空格结尾, 我们可以用rfind来查找最后一个空格,利用rfind找不到返回npos作为判断条件

#include <iostream>
using namespace std;
#include<string>
int main() {
   string s;
   cin >> s;
   size_t pos = s.rfind(' ');
   if(pos != string::npos)
   {
    cout<<s.size()-pos-1<<endl;
   }
   else 
   cout<<s.size()<<endl;
}

注意这里输出单词要去掉空格,也就是-1。

 记住,两个下标相减,得到的长度是一个左闭右开的区间。

但这段代码是有问题的,我们都知道scanf遇到空格或\n会停止,cin也是如此,为了避免这一问题,我们可以使用c++的getline函数,这样就可以将string以整行的方式输出了。

第一个可以自定义结束标志,换行为通用结束标志

  getline(cin,s);

字符串相加 

注意这里的限制条件,明确告诉我们不能用整数及相应的库的形式,我们可以像小学计算两个数个位十位百位分别相加,满则进1。

从后往前加,判断条件是两个数都达到最高位停止

string addStrings(string num1, string num2) {
        int end1 = num1.size()-1,end2 = num2.size()-1;
         string str;
        while(end1>=0 || end2>=0)
        {}

注意这里用表示结束条件

利用ascii码的顺序性,可以将起始位置设成 '0',相减就能得到进行相加的值,因为要多次循环,所以要判断下表位置是否加到了0位

            int val1 = end1 >= 0 ? num1[end1]-'0':0;
            int val2 = end2 >= 0 ? num2[end2]-'0':0;
            int ret = val1 + val2;

因为涉及进位,我们在内外定义一个next变量控制进位,ret也要加上next

这里我们可以用0,1来控制next:

            if(ret>9)
            {
                next = 1;
                ret = ret%10;
            }
            else
            {
                next = 0;
            }

用else将next置0是为了第二次不满足进位条件时不能还是加1

第二种方法:

next = ret / 10;

插入数据并推动循环:

            str.insert(0,1,ret+'0');//首插
            //str.insert(str.begin(),ret+'0');
            --end1;
            --end2;

注意如果两个位数一样的在最后一次循环后发生进位是无法被计算的,这里我们在循环外判断这种情况

        if(next == 1)
        {
            str.insert(0,1,'1');
        }

代码能够正常运行,但存在效率问题,头插的n^2消耗还是挺大的,所以我们可以采用尾插+reverse的组合优化。如果遇到过大的数据需要进行扩容,我们这里提前开好空间是不是也能减少消耗呢?(可以选择以最大位为标准)

 完整代码:

class Solution {
public:
    string addStrings(string num1, string num2) {
        int end1 = num1.size()-1,end2 = num2.size()-1;
        int next=0;
         string str;
         str.reserve(num1.size()>num2.size() ? num1.size()+1:num2.size()+1);
         //str.reserve(end1>end2 ? num1.size()+1:num2.size()+1);
        while(end1>=0 || end2>=0)
        {
            int val1 = end1 >= 0 ? num1[end1]-'0':0;
            int val2 = end2 >= 0 ? num2[end2]-'0':0;
            int ret = val1 + val2 + next;
               next = ret/10;
                ret = ret%10;
          
           //str.insert(0,1,ret+'0');//首插
           //str.insert(str.begin(),ret+'0');
           str += ret+'0';
            --end1;
            --end2;
        }
        if(next == 1)
        {
           // str.insert(0,1,'1');
           str+='1';
        }
        reverse(str.begin(),str.end());
        return str;
    }
};


 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小C您好

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值