0710算法 - 字符串01

344.反转字符串 | 541. 反转字符串II | 54.替换数字

Posted by ZA on July 10, 2024

前言

一组比较基础的字符串类型题目

344. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须 原地 修改输入数组 、使用 O(1) 的额外空间解决这一问题。

思路

  • reverse函数的内部实现 reverse(s.begin(),s.end());

拓展知识

字符串类 string s1; 和容器类 vector<char> s2; 的区别

  • string 用于表示可变长度的字符 序列。拥有丰富的字符串操作方法,适用于文本处理、字符串拼接、字符串查找等场景
  • vector<char> 用于表示可变长度的字符 数组。仅能使用数组操作方法,但可以使用指针,适用于二进制数据处理、数组操作等场景

代码实现

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

        while(i<j){
            temp = s[i];
            s[i] = s[j];
            s[j] = temp;
            i++;
            j--;
        }
    }
};

整理格式后:

class Solution {
public:
    void reverseString(vector<char>& s) {
        for (int i = 0, j = s.size() - 1; i < j; i++, j--) {
            swap(s[i],s[j]);
        }
    }
};

541. 反转字符串 II

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

思路

看起来条件很多,但其实可以合并:

  • 剩余字符在 >2k<2k 处理上没有区别,都是翻转前 k 个。因为有 i<s.size() ,即使 <2k+(2*k) 也不会溢出
  • 只在 >=k<k 的处理上产生分支,一个翻转前k,一个翻转剩余所有

因此最终在for循环中只需要设置 >=k<k 两个条件判断

代码实现

class Solution {
public:
    string reverseStr(string s, int k) {
        for(int i=0; i<s.size(); i+=(2*k)){
            // 1. 每计数 2k 个字符就翻转前 k 个
            // 2. 剩余字符大于等于 k 个,同样翻转前 k 个
            if(s.size()-i >= k){
                reverse(s.begin()+i, s.begin()+i+k);
            }
            // 3. 剩余字符小于 k 个,则全部翻转
            else{
                reverse(s.begin()+i, s.end());
            }
        }
        return s;
    }
};

54. 替换数字

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number

例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"

难点

  • 如何不借助额外辅助空间?

思路

  • 对于定长的字符串,可以通过统计数字个数以预留空间,实现原地拓展

    • 关键函数:s.resize(s.size() + count*5);
  • 从头遍历的双指针法,每次查找到数字,都要将后续所有字符向后移动5位,效率极低。因此可以尝试从尾部遍历,预留空间必定会在未来被填满,因此直接移动至尾部,实现一次移动至最终位置。

代码实现

#include <iostream>
using namespace std;

int main(){
    string s;
    while(cin>>s){
        int left = s.size()-1;
        int count = 0;
        for(int i=0; i<s.size(); i++){
            if(s[i]>'0' && s[i]<'9'){
                count++;
            }
        }
        
        // 6个字符,除了数字自己的空间,还要额外扩展5个
        s.resize(s.size() + count*5); 
        int right = s.size()-1;
        while(left >= 0){
            if(s[left]>'0' && s[left]<'9'){
                s[right--] = 'r';
                s[right--] = 'e';
                s[right--] = 'b';
                s[right--] = 'm';
                s[right--] = 'u';
                s[right--] = 'n';
            }
            else{
                s[right--] = s[left];
            }
            left--;
        }
        cout<< s << endl;
    }
}
    

参考