7.反转字符串、替换数字

反转字符串(leetcode第344题)

题目

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

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

你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

示例 1:
输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]

示例 2:
输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]

思路

我的思路就是双指针,一前一后。

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

很简单

反转字符串2(leetcode第541题)

题目

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

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

示例 1:

输入:s = "abcdefg", k = 2
输出:"bacdfeg"

示例 2:

输入:s = "abcd", k = 2
输出:"bacd"

思路

我的思路是快慢指针,然后有一个bool值记录这个k之内该不该反转,然后处理一下临界情况就行。

class Solution {
public:
    string reverseStr(string s, int k) {
        int count=0;
        bool rev=1;
        for(int i=0;i<s.size();i++){
            count++;
            if(count==k&&rev){
                int right=i;
                int left=i+1-k;
                while(left<right){
                    char tmp=s[left];
                    s[left]=s[right];
                    s[right]=tmp;
                    left++;
                    right--;
                }
                count=0;
                rev=0;
            }else if(count==k&&!rev){
                count=0;
                rev=1;
            }else if(i==s.size()-1&&rev){
                int right=i;
                int left=i+1-count;
                if(left<0)left=0;
                while(left<right){
                    char tmp=s[left];
                    s[left]=s[right];
                    s[right]=tmp;
                    left++;
                    right--;
                }
                count=0;
                rev=0;
            }
        }
        return s;
    }
};

替换数字(卡码网第54题)

题目

题目描述

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 “a1b2c3”,函数应该将其转换为 “anumberbnumbercnumber”。

输入描述

输入一个字符串 s,s 仅包含小写字母和数字字符。

输出描述

打印一个新的字符串,其中每个数字字符都被替换为了number

输入示例
a1b2c3
输出示例
anumberbnumbercnumber
提示信息

数据范围:
1 <= s.length < 10000。

思路

做这道题之前,我了解了一下c++字符串操作的库函数

在C++中,字符串操作可以通过C风格字符串函数(位于 头文件)和C++的 std::string 类(位于 头文件)实现。以下是常用库函数和方法的分类介绍:


一、C风格字符串函数(

C风格字符串以 \0(空字符)结尾,操作时需注意内存管理和安全性。

1. 基本操作
  • strlen(const char* str)
    返回字符串长度(不包含 \0)。

    char s[] = "Hello";
    int len = strlen(s); // len = 5
    
  • strcpy(char* dest, const char* src)
    src 复制到 dest(需确保 dest 空间足够)。
    更安全的替代strncpy(dest, src, n)(复制最多 n 个字符)。

    char dest[10];
    strcpy(dest, "Hello"); // dest = "Hello"
    
  • strcat(char* dest, const char* src)
    src 追加到 dest 末尾。
    更安全的替代strncat(dest, src, n)

    char dest[10] = "Hello";
    strcat(dest, "!"); // dest = "Hello!"
    
  • strcmp(const char* s1, const char* s2)
    比较字符串:

    • 返回 0(相等)、>0(s1 > s2)或 <0(s1 < s2)。
    int result = strcmp("apple", "banana"); // result < 0
    
2. 查找与分割
  • strchr(const char* str, int c)
    返回字符 cstr 中首次出现的位置指针,未找到返回 nullptr

    char* p = strchr("Hello", 'l'); // 指向第一个 'l' 的位置
    
  • strstr(const char* haystack, const char* needle)
    返回子串 needlehaystack 中首次出现的位置指针。

    char* p = strstr("Hello World", "World"); // 指向 "World"
    
  • strtok(char* str, const char* delim)
    按分隔符 delim 分割字符串(线程不安全)。

    char str[] = "a,b,c";
    char* token = strtok(str, ","); // token依次为 "a", "b", "c"
    
3. 内存操作
  • memset(void* ptr, int value, size_t num)
    ptr 指向的内存的前 num 字节设置为 value

    char buffer[10];
    memset(buffer, 0, sizeof(buffer)); // 全部初始化为0
    
  • memcpy(void* dest, const void* src, size_t num)
    src 复制 num 字节到 dest(不处理重叠区域)。

    char src[] = "Copy";
    char dest[5];
    memcpy(dest, src, 5); // dest = "Copy"
    

二、C++的 std::string 类(

std::string 自动管理内存,更安全且功能丰富。

1. 构造与赋值
  • string(const char* s)
    从C风格字符串构造。

    std::string s = "Hello";
    
  • assign()
    赋值操作。

    s.assign("World");
    
2. 修改操作
  • append() / +=
    追加字符串。

    s.append("!"); // s = "Hello!"
    s += "!!";     // s = "Hello!!!"
    
  • insert(size_t pos, const string& str)
    在指定位置插入字符串。

    s.insert(5, " World"); // "Hello World"
    
  • replace(size_t pos, size_t len, const string& str)
    替换子串。

    s.replace(6, 5, "There"); // "Hello There"
    
  • erase(size_t pos = 0, size_t len = npos)
    删除子串。

    s.erase(5, 6); // s = "Hello"
    
3. 查找与子串
  • find(const string& str, size_t pos = 0)
    查找子串,返回起始索引(未找到返回 string::npos)。

    size_t idx = s.find("World"); // idx = 6
    
  • substr(size_t pos = 0, size_t len = npos)
    提取子串。

    std::string sub = s.substr(6, 5); // sub = "World"
    
4. 其他操作
  • compare(const string& str)
    比较字符串(类似 strcmp)。

    int res = s.compare("Hello"); // 0(相等)
    
  • c_str()
    返回C风格字符串(以 \0 结尾)。

    const char* cstr = s.c_str();
    
  • stoi(), stol(), stof()
    将字符串转换为数值。

    int num = std::stoi("123"); // num = 123
    

三、其他实用函数

  • std::getline()
    读取一行输入(可处理空格)。

    std::string input;
    std::getline(std::cin, input);
    
  • std::to_string()
    将数值转换为字符串。

    std::string num_str = std::to_string(42); // "42"
    
  • std::string_view(C++17)
    提供对字符串的非拥有视图,避免拷贝。

    std::string_view view = "Hello";
    

四、注意事项

  1. C风格函数的安全问题
    strcpystrcat 等易导致缓冲区溢出,建议使用 strncpystrncat 或优先选择 std::string
  2. 内存管理:C风格字符串需手动分配/释放内存,std::string 自动管理。
  3. 性能std::string 操作可能涉及动态内存分配,高频操作时需注意效率。

推荐实践:优先使用 std::string 和 C++标准库,避免直接操作C风格字符串,以提高代码安全性和可维护性。

我的代码实现:

#include 
#include 
using namespace std;
int main(){
	string s;
    cin>>s;
    for(int i=0;i<s.size();i++){
        
    	if(s[i]>='0'&&s[i]<='9'){
            //if(i>0&&s[i-1]>='0'&&s[i-1]<='9')continue;
        	cout<<"number";
        }else{
        	cout<<s[i];
        }
    }
}

很简单

对比反思

我的做法是直接输出,相当于使用了额外的内存空间,代码随想录上面使用的双指针法:

先扩充好空间,快指针探路,慢指针填充;

#include 
using namespace std;
int main() {
    string s;
    while (cin >> s) {
        int sOldIndex = s.size() - 1;
        int count = 0; // 统计数字的个数
        for (int i = 0; i < s.size(); i++) {
            if (s[i] >= '0' && s[i] <= '9') {
                count++;
            }
        }
        // 扩充字符串s的大小,也就是将每个数字替换成"number"之后的大小
        s.resize(s.size() + count * 5);
        int sNewIndex = s.size() - 1;
        // 从后往前将数字替换为"number"
        while (sOldIndex >= 0) {
            if (s[sOldIndex] >= '0' && s[sOldIndex] <= '9') {
                s[sNewIndex--] = 'r';
                s[sNewIndex--] = 'e';
                s[sNewIndex--] = 'b';
                s[sNewIndex--] = 'm';
                s[sNewIndex--] = 'u';
                s[sNewIndex--] = 'n';
            } else {
                s[sNewIndex--] = s[sOldIndex];
            }
            sOldIndex--;
        }
        cout << s << endl;       
    }
}

从后往前

你可能感兴趣的:(数据结构)