字符串反转(反转,替换,反转单词,左旋)

哈喽!今天我们来聊聊一个非常有趣的话题——反转字符串!我们在日常生活中经常会遇到需要将字符串颠倒过来的情况,比如翻转一句话或者颠倒一个名字的顺序。这个时候,就可以用到反转字符串算法了。

首先,让我们来思考一下这个算法的实现。最简单直接的方式是使用一个循环,从字符串的末尾开始,将每个字符逐个放到一个新的字符串中。不过,这个方法看起来有点笨重,我们有更聪明的办法。

让我们来尝试一个巧妙的思路。我们可以定义两个指针,一个指向字符串的开头,一个指向字符串的末尾。然后,我们将这两个指针指向的字符进行交换,直到两个指针相遇为止。通过这种方式,我们可以逐步实现字符串的反转。

具体来说,我们可以从字符串的两端开始,依次交换它们指向的字符。每次交换完之后,两个指针向中间靠拢一步,直到它们相遇。这样,整个字符串就被完美地颠倒过来了。

好了,现在让我们来看一下具体的实现代码。假设我们的字符串是一个可变字符数组,首先我们需要定义两个指针,一个指向字符串开头的位置,一个指向字符串结尾的位置。然后,我们可以使用一个循环来依次交换两个指针指向的字符,直到两个指针相遇为止。

下面是实现代码:

class Solution {
public:
    void reverseString(vector<char>& s) {
        int left = 0;
        int right = s.size() - 1;

        while (left < right)
        {
            swap(s[left],s[right]);
            left++;
            right--;
        }
        
    }
};

我们接着来聊聊一道相关的题目——541. 反转字符串 II。这道题是对刚才我们提到的反转字符串算法的一个扩展。

题目要求我们对给定的字符串进行一种特殊的反转操作,具体来说,是将字符串中的每间隔 2k 个字符的前 k 个字符进行反转。换句话说,我们需要把每个长度为 k 的子串进行反转,而保留其它部分的字符顺序不变。

这个题目的解题思路其实与我们之前提到的反转字符串算法类似,但稍加变化。需要改变循环时的一些变量。但整体循环变量自己理解就行,不同人写法可能不同。

class Solution {
public:
    string reverseStr(string s, int k) {
        
        int start = 0;
        int end = start + k;
        while(start < s.size())
        {
            if(end > s.size())
            {
                reverse(s.begin() + start,s.end());
            }
            else
            {
                reverse(s.begin() + start,s.begin() + end);
            }
            start = start + 2 * k;
            end = end + 2 * k;
        }
        return s;
    }
};

接下来让我们继续进行替换空格的练习吧!

通常来讲,我们确实是可以用replace来进行基础的操作,但是面试中,还是最好以双指针法经验面试官。

这道题目要求我们替换字符串中的空格,要求以时间复杂度O(N)和空间复杂度O(1)的方式进行。我们可以使用双指针法来解决这个问题。

具体的步骤如下:

  1. 遍历字符串,统计空格的个数,计算出替换后的字符串的总长度;
  2. 创建一个新的字符数组,长度为原字符串的总长度,并将原字符串的字符依次复制到新数组中;
  3. 使用两个指针,一个指向原字符串的末尾,另一个指向新数组的末尾;
  4. 从后向前遍历新数组,当遇到空格时,将"%20"依次插入指针指向的位置,并分别向前移动指针;
  5. 最后,将新数组转换为字符串并返回。

下面是实现代码:

class Solution {
public:
    string replaceSpace(string s) {
        int count = 0;
        int oldsize = s.size();
        for(int i = 0; i < s.size(); i++)
        {
            if (s[i] == ' ')
            {
                count++;
            }
        }
        s.resize(s.size() + count * 2);   
        int newsize = s.size();
        int j = oldsize; 
        int i = newsize;
        while ( j < i && j >= 0)
        {
            if(s[j] != ' ')
            {
                s[i] = s[j];
                i = i - 1;
                j = j - 1;
            }
            else
            {
                s[i] = '0';
                s[i-1] = '2';
                s[i-2] = '%';
                i = i - 3;
                j = j - 1;
            }
        }
        std::cout << "my new string" << s << endl;
        return s;
    }
};

下面我们来看151.反转字符串中的单词

这道题目要求我们反转字符串中的单词顺序,要求不使用额外的空间,只在原字符串上进行操作。我们可以使用双指针法来解决这个问题。

具体的步骤如下:

  1. 先将字符串整体反转;
  2. 使用两个指针,一个指向当前单词的起始位置,一个指向当前单词的结束位置;
  3. 遍历字符串,当遇到空格时,将当前单词进行反转,并更新下一个单词的起始位置;
  4. 最后一个单词没有空格,所以需要单独进行反转。

下面是实现代码

class Solution {
public:
    string removeExtraSpace(string s)
    {
        int fastIndex = 0;
        int slowIndex = 0;
        for(;fastIndex < s.size(); fastIndex++)
        {
            if(s[fastIndex] != ' ')
            {
                break;
            }
        }
        for(;fastIndex < s.size(); fastIndex++)
        {
            if(fastIndex > 0 && s[fastIndex] == ' ' && s[fastIndex-1] == ' ')
            {
                ;
            }
            else
            {
                s[slowIndex] = s[fastIndex];
                slowIndex++;
            }        
        }
        if (slowIndex > 1 && s[slowIndex-1] == ' ')
        {
            s.resize(slowIndex-1);
        }
        else
        {
            s.resize(slowIndex);
        }
        return s;
    }
    string reverseWords(string& s) {
        string new_s = removeExtraSpace(s);
        reverse(new_s.begin(), new_s.end());
        int start = 0;
        for (int i = 0; i < new_s.size(); i++) {
            if (new_s[i] == ' ') { 
                reverse(new_s.begin() + start, new_s.begin() + i); 
                start = i + 1; 
            }
        }
        reverse(new_s.begin() + start, new_s.end()); 
        return new_s;
    }
};

下面我们来看,剑指Offer58-II.左旋转字符串题目。

这道题目要求我们将一个字符串的前n个字符移到字符串的末尾,实现字符串的左旋转操作。我们可以通过字符串切片和字符串拼接的方式来解决这个问题。

具体的步骤如下:

  1. 使用字符串切片,将字符串分为前n个字符和剩余的字符两部分;
  2. 将剩余的字符与前n个字符拼接,即可得到左旋转后的字符串。

 但如果要求我们在原字符串上进行操作,不能申请额外空间。

针对这个要求,我们可以利用字符串的翻转操作来实现左旋转字符串。

具体的步骤如下:

  1. 先将整个字符串的前n反转;
  2. 再将后n个字符进行反转;
  3. 最后将整个进行反转。
class Solution {
public:
    string reverseLeftWords(string s, int n) {
        reverse(s.begin(),s.begin() + n);
        reverse(s.begin() + n , s.end());
        reverse(s.begin(),s.end());
        return s;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值