学习花式反转——字符串

  • 序:有的时候调用库中直接给的类方法解决起来更轻松,有的时候里面的方法并不能解决实际性问题,这时候就需要我们自个儿重写了。首先我们可以学习库里面方法怎么实现的,随后我们可以写出不同于它的(别人的东西不一定有自个儿的好)下面说说c++STL中string和Java中的String与StringBuffer解决反转问题所遇到的情况。

咱现在就从题入手,进行解释

LeetCode 344.反转字符串

(玩呢?我直接调个c++reverse库函数不就解决了吗?(reverse(s.begin(),s.end()) 就这?)

先不急,咱先掌握其实现原理,后续肯定是有用的。

如何反转呢?我们是不是可以利用双指针对左右进行交换,让双指针向中间靠拢。

实现代码:

class Solution {
public:
    void reverseString(vector<char>& s) {
        int left = 0;
        int right = s.size() - 1;
        while(left<right){//当left等于right或者left大于right就不需要进行交换了已经反转完毕了
        swap(s[left],s[right]);//交换元素
        ++left;
        --right;
        }
    }
};

交换数据有三种常见的方法:

1. 创建第三变量

int temp = s[left];

s[left] = s[right];

s[right] = temp;

2. 用加法运算(但可能导致数据溢出)

s[left] = s[left] + s[right];

s[right] = s[left] - s[right];

s[left] = s[left] - s[right];

3. 采用位运算(异或^)

s[left] ^= s[right];

s[right] ^= s[left];

s[left] ^= s[right];

(第一种是最好的,不受类型限制,用异或不能解决float等数据类型的数据,数据不大的情况下,第一种更好)

现在掌握了反转字符串的原理,思考一下如果是只反转字符串片段呢?c++中reverse是可以解决这一反转的,但是Java中StringBuffer是不能选取字符串片段进行反转的,接下来看题:

LeetCode 541.反转字符串 ||

 这题用c++库还是蛮简单的,首先我们定一下反转的起始位置,每反转一次起始位置就开始变化(左右俩次反转的距离是2*k),然后再确定反转的末位置,如果反转字符小于k了,那就反转起始位置到字符串尽头(s.size()),如果大于k的话,那末位置就是起始位置+k。

C++代码如下:

class Solution {
public:
    string reverseStr(string s, int k) {
        int start = 0;
        int end;
        while(start<s.size()){
            end = start + k;
            //反转末位置在长度之内则反转该序列
            if(end<=s.size()){
                reverse(s.begin()+start,s.begin()+end);
            }
            //不在长度之内则说明,反转序列小于k,直接把起始位置到字符串尽头都反转
            else
            reverse(s.begin()+start,s.end());
            start += 2*k;
        }
        return s;
    }
};

如果我们想用Java提供的库方法呢?咱就得采用拼接的形式:

Java采用库的代码如下:

class Solution {
    public String reverseStr(String s, int k) {
        String xs = new String(); //用来存取反转的字符串(也可以说是对字符串s进行重新拼接)
        int start = 0; //一样的,定义起始位置
        while(start<s.length()){
            StringBuffer acts = new StringBuffer();//定义一个动态字符串,进行翻转操作
            //但这里得注意需要给出两个变量,一个是反转的末位置,一个是不用反转的莫位置
            int _start = start+k<s.length()?start+k:s.length();
            int end = start+2*k<s.length()?start+2*k:s.length();

            //存取加反转操作
            acts.append(s.substring(start,_start));
            acts.reverse();
            xs += acts.toString();

            start += 2*k; //更新初始位置
            if(_start<end)
            xs += s.substring(_start,end);
        }
        return xs;
    }
}

这样写真是费时费力不讨喜。 

那Java库中没有提供片段式反转,那么我们可以怎样?自己写一个方法实现呗,题1说了反转实现的原理,外加俩参数定义需要反转的区间就可以了。

接下来看代码,更好理解:

class Solution {
    //反转
    private void reverseS(char[] s,int left,int right){
        while(left<right){
            char ch = s[left];
            s[left] = s[right];
            s[right] = ch;
            ++left;
            --right;
        }
    }
    public String reverseStr(String s, int k) {
        int start = 0;
        int end;
        char[] ss = s.toCharArray();//转化成数组进行操作 
        //模拟上面c++写的就行了
        while(start<s.length()){
            end = start + k;
            if(end<ss.length){
                reverseS(ss,start,end-1);//这里注意这里和库里面的反转不一样,这里的末尾是反转序列最后一个数据,而不是最后一个再往后一个
            }
            else
            reverseS(ss,start,ss.length-1);
            start += 2*k;
        }
        return new String(ss);//根据构造函数String(char[])将字符数组转化成字符串
    }
}

接下来咱拿它去练手:

LeetCode 151.反转字符串中的单词

 这题第一步肯定先得去除额外的空格,因为最后结果字符串单词之间最多只能有一个空格。

有俩种想法可以尝试了:

第一种:先将各个单词存入容器中,把单词看成容器里面的元素,然后进行反转就🆗了(这个c++写起来比较轻松)

第二种:先总的反转,然后再将每个单词进行反转,这样也可以得到同样的结果

(这里为了联系上文,只写第二种,第一种有疑问可以发私信,一起交流学习)

代码如下:

class Solution {
    //去除字符串s中多余出来的空格
    private StringBuffer removeExtraSpace(String s){
        s = s.trim(); //去除s的首尾空格
        StringBuffer ss = new StringBuffer(s);
        //去除ss|s中间多余的空格
        for(int i=ss.length()-1;i>=1;--i){
            if(s.charAt(i)==' '&&s.charAt(i-1)==' ')
            ss.delete(i,i+1);
        }
        return ss;
    }
    //反转字符串序列方法
    private void reverseS(StringBuffer ss,int left,int right){
        while(left<right){
            char temp = ss.charAt(left);
            ss.setCharAt(left,ss.charAt(right));
            ss.setCharAt(right,temp);
            ++left;
            --right;
        }
    }
    //反转单词
    private void reverseWords(StringBuffer ss){
        int left = 0;
        for(int right = 0;right<ss.length();++right){
            if(ss.charAt(right)==' '){
                reverseS(ss,left,right-1);
                left = right + 1;
            }
            else
            continue;
        }
        //给最后一个单词反转
        reverseS(ss,left,ss.length()-1);
    }
    public String reverseWords(String s) {
        StringBuffer ss = removeExtraSpace(s);
        ss.reverse();
        reverseWords(ss);
        return ss.toString();
    }
}

再推荐一题练手,和上述方法一样的(当然方法不唯一):

剑指 Offer 58 - ||.左旋转字符串

看完这个有没有想看库里面源码的冲动 ​​​​​😍😍😍

 

点个小赞赞鼓励一下😆😆😆让我知晓你来过👩‍💻

我的主页🎈🎈🎈

 

 

 

 

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

假正经的小柴

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

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

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

打赏作者

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

抵扣说明:

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

余额充值