c/c++蓝桥杯经典编程题100道(6)字符串反转

字符串反转

->返回c/c++蓝桥杯经典编程题100道-目录


目录

字符串反转整理

一、题型解释

二、例题问题描述

C语言实现

解法1:双指针交换法(难度★)

解法2:递归反转(难度★★)

解法3:使用临时数组(难度★☆)

C++实现

解法1:使用reverse函数(难度★)

解法2:用栈反转(难度★☆)

解法3:反转句子中的单词(难度★★★)

特殊案例:只反转字母

总结对比表


一、题型解释

字符串反转是将原字符串的字符顺序完全颠倒的操作。常见

题型:

  1. 基础反转:将整个字符串完全反转(如 "hello" → "olleh")。

  2. 部分反转:反转字符串中的某个子区间(如反转前k个字符)。

  3. 单词级反转:按单词为单位反转(如 "hello world" → "world hello")。

  4. 特殊条件反转:保留特定字符位置不变(如仅反转字母,保留数字和符号)。


二、例题问题描述

例题1:输入字符串 s(假设只含小写字母),输出其完全反转后的字符串。
例题2:输入字符串 s(含空格),按单词反转顺序,如 "the sky is blue" → "blue is sky the"


C语言实现

解法1:双指针交换法(难度★)

就像两个同学从两头交换纸条

c

#include 
#include  // 要用strlen函数

void reverseString(char* s) {
    int left = 0;                   // 左边的同学从第一个字符开始
    int right = strlen(s) - 1;      // 右边的同学从最后一个字符开始
    
    // 当左边同学还在右边同学左边时,继续交换
    while (left < right) {
        // 交换两人的纸条(字符)
        char temp = s[left];        // 临时保管左边的字符
        s[left] = s[right];         // 左边的位置放右边的字符
        s[right] = temp;            // 右边的位置放临时保管的字符
        
        left++;  // 左边同学往右走一步
        right--; // 右边同学往左走一步
    }
}

int main() {
    char s[] = "hello"; // 要反转的字符串
    reverseString(s);
    printf("%s", s); // 输出 olleh
    return 0;
}

代码逻辑

  1. 指针初始化left 指向字符串头部,right 指向尾部(需用 strlen 计算长度)。

  2. 交换过程:每次交换 left 和 right 位置的字符,之后 left 右移、right 左移。

  3. 终止条件:当 left >= right 时停止,确保所有字符被处理一次。

  4. 时间复杂度:O(n),空间复杂度 O(1)。

通俗解释

  1. 想象字符串是一排座位,每个座位坐一个字符

  2. 让最左边的同学(left)和最右边的同学(right)交换手里的字符

  3. 交换后,左边同学向右移动,右边同学向左移动

  4. 重复这个过程,直到两个同学相遇或交叉


解法2:递归反转(难度★★)

就像传话游戏,每次让第一个和最后一个交换,中间交给下个人处理

c

#include 
#include 

void reverseHelper(char* s, int left, int right) {
    if (left >= right) return; // 如果只剩一个字符或没有字符,结束
    
    // 交换第一个和最后一个字符
    char temp = s[left];
    s[left] = s[right];
    s[right] = temp;
    
    // 把剩下的中间部分交给下一次递归处理
    reverseHelper(s, left + 1, right - 1);
}

void reverseString(char* s) {
    reverseHelper(s, 0, strlen(s) - 1);
}

int main() {
    char s[] = "hello";
    reverseString(s);
    printf("%s", s); // 输出 olleh
    return 0;
}

代码逻辑

  1. 递归定义:每次交换首尾字符,然后递归处理中间子串。

  2. 终止条件:当左右指针相遇或交叉时结束递归。

  3. 栈空间风险:递归深度为 O(n/2),若字符串过长可能导致栈溢出。

通俗解释

  1. 每次处理字符串的首尾字符,把它们交换

  2. 然后把剩下的中间部分看作一个新的字符串,重复这个过程

  3. 就像剥洋葱,每次处理最外层,直到洋葱芯(只剩一个字符)


解法3:使用临时数组(难度★☆)

就像把积木倒过来重新排列

c

#include 
#include 

void reverseString(char* s) {
    int len = strlen(s);
    char temp[len + 1]; // 准备一个和原字符串一样大的临时数组
    
    // 倒着复制字符到临时数组
    for (int i = 0; i < len; i++) {
        temp[i] = s[len - 1 - i]; // 原数组最后一个字符放到临时数组第一个位置
    }
    temp[len] = '\0'; // 添加字符串结束标志
    
    strcpy(s, temp); // 把临时数组的内容复制回原数组
}

int main() {
    char s[] = "hello";
    reverseString(s);
    printf("%s", s); // 输出 olleh
    return 0;
}

代码逻辑

  1. 空间换时间:创建临时数组存储逆序结果,再拷贝回原字符串。

  2. 时间复杂度:O(n),但空间复杂度为 O(n),适用于不允许修改原字符串的场景。

通俗解释

  1. 新建一个空白数组(就像一排新座位)

  2. 从原字符串最后一个字符开始,一个一个放到新数组的前面

  3. 最后把新数组的内容整个复制回原数组


C++实现

解法1:使用reverse函数(难度★)

直接使用现成的工具

cpp

#include 
#include  // 包含reverse函数
using namespace std;

int main() {
    string s = "hello";
    reverse(s.begin(), s.end()); // 告诉函数从哪里开始反转,到哪里结束
    cout << s; // 输出 olleh
    return 0;
}

代码逻辑

  • 直接调用 algorithm 库中的 reverse 函数,传入迭代器范围 [begin, end)

  • 底层实现为双指针原地交换,时间复杂度 O(n)。

通俗解释

  • s.begin() 是字符串的起点(第一个字符)

  • s.end() 是字符串终点的后一个位置(类似下课铃的位置)

  • reverse 函数会自动帮你完成交换


解法2:用栈反转(难度★☆)

就像把书一本本堆起来再拿下来

cpp

#include 
#include 
using namespace std;

string reverseString(string s) {
    stack st; // 准备一个栈(就像书堆)
    
    // 把每个字符像书一样叠起来
    for (char c : s) {
        st.push(c);
    }
    
    // 把书一本本拿下来,顺序就反过来了
    for (int i = 0; i < s.size(); i++) {
        s[i] = st.top(); // 拿最上面的书
        st.pop();        // 拿掉后栈顶变成下一本
    }
    
    return s;
}

int main() {
    string s = "hello";
    cout << reverseString(s); // 输出 olleh
    return 0;
}

代码逻辑

  1. 栈的特性:将所有字符依次压入栈,再依次弹出实现逆序。

  2. 时间复杂度:O(n),但需要额外 O(n) 的栈空间。

通俗解释

  1. 栈就像叠盘子,最后放上去的盘子(字符)会最先被拿走

  2. 把原字符串的字符一个个放入栈

  3. 再按出栈顺序重新排列字符


解法3:反转句子中的单词(难度★★★)

先拆成单词,再倒序组装

cpp

#include 
#include 
#include 
using namespace std;

string reverseWords(string s) {
    vector words; // 用来装单词的容器
    stringstream ss(s);   // 把字符串变成"字符流"
    string word;
    
    // 像用剪刀剪开字符串,按空格分割成单词
    while (ss >> word) {
        words.push_back(word); // 把单词放进容器
    }
    
    reverse(words.begin(), words.end()); // 反转容器里的单词顺序
    
    string result;
    for (int i = 0; i < words.size(); i++) {
        if (i != 0) result += " "; // 单词之间加空格(第一个单词不加)
        result += words[i];
    }
    return result;
}

int main() {
    string s = "the sky is blue";
    cout << reverseWords(s); // 输出 blue is sky the
    return 0;
}

代码逻辑

  1. 字符串分割:使用 stringstream 按空格分割字符串为单词列表。

  2. 反转单词顺序:调用 reverse 反转单词列表。

  3. 拼接结果:将反转后的单词用空格连接成新字符串。

  4. 处理连续空格ss >> word 会自动跳过连续空格。

通俗解释

  1. 把原字符串看成用空格分隔的多个单词

  2. 用 stringstream 像剪刀一样剪开这些单词

  3. 把单词放进一个盒子(vector)里,反转盒子的顺序

  4. 最后把单词按顺序粘回去,中间加空格


特殊案例:只反转字母

跳过非字母字符,就像绕开障碍物

cpp

#include 
using namespace std;

bool isLetter(char c) {
    // 判断是否是字母:A-Z或a-z之间
    return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}

string reverseOnlyLetters(string s) {
    int left = 0, right = s.size() - 1;
    
    while (left < right) {
        // 左边找字母:如果不是字母就跳过
        while (left < right && !isLetter(s[left])) left++;
        
        // 右边找字母:如果不是字母就跳过
        while (left < right && !isLetter(s[right])) right--;
        
        // 交换找到的字母
        swap(s[left], s[right]);
        
        left++;
        right--;
    }
    return s;
}

int main() {
    string s = "a1b2c3";
    cout << reverseOnlyLetters(s); // 输出 c1b2a3
    return 0;
}

代码逻辑

  • 双指针法基础上增加字符类型判断,仅交换字母字符。

  • 时间复杂度 O(n),空间复杂度 O(1)。

通俗解释

  1. 两个同学从两头出发,但只交换字母

  2. 左边同学如果看到数字或符号,就向右走一步

  3. 右边同学同理,直到两人都找到字母才交换


总结对比表

方法 适用场景 优点 缺点
双指针交换 简单快速的整体反转 不占额外内存 需要理解指针操作
递归 理解递归原理 代码简洁 处理长字符串可能崩溃
临时数组 保留原字符串不变时 逻辑直观 需要双倍内存
标准库reverse 快速实现 一行代码解决问题 不适用于特殊需求
栈反转 理解栈的特性 直观展示后进先出 效率略低
单词反转 处理句子中的单词顺序 自动处理空格

需要理解字符串分割

->返回c/c++蓝桥杯经典编程题100道-目录

你可能感兴趣的:(c语言,c++,蓝桥杯,算法)