前言
处理字符串主要是有思路,同时总结方法。
题目链接
151. 反转字符串中的单词 - 力扣(LeetCode)
55. 右旋字符串(第八期模拟笔试)
一、翻转字符串里的单词
这个题目的主要思路,代码采用从后往前遍历字符串的方式,逐个提取单词并按反转顺序添加到新的字符串中,同时妥善处理了空格相关的问题,最终得到符合要求的输出字符串。
具体步骤:
初始化与循环准备:首先获取输入字符串
s
的长度,并将用于遍历字符串的索引i
初始化为字符串最后一个字符的位置(i = s.size() - 1
)。同时创建一个空字符串ans
,用来存储最终处理好的结果。外层循环(处理每个单词):通过
while(i >= 0)
这个外层循环来依次处理字符串中的每个单词。从字符串末尾开始向前遍历,这个循环会持续执行,直到整个字符串都被处理完(也就是i
小于 0 时结束)。跳过末尾空格:在每次开始处理一个新的可能的单词前,有一个内层的
while
循环while(i >= 0 && s[i] == ' ') --i;
,它的作用是跳过字符串末尾连续出现的空格。比如字符串最后可能跟着多个空格,要先把这些空格跳过,找到真正最后一个单词的最后一个字符位置。确定单词长度:紧接着另一个内层
while
循环while(i >= 0 && s[i]!= ' ') --i, ++c;
,这个循环从刚才跳过空格后的位置开始,继续向前遍历,只要当前字符不是空格(意味着还处于同一个单词内),就继续向前移动索引i
,同时用计数器c
记录当前单词的字符个数。例如对于单词"blue"
,这个循环会统计出它包含 4 个字符。提取并添加单词到结果字符串:如果计数器
c
不为 0,说明找到了一个有效的单词,那么通过s.substr(i + 1, c)
提取出这个单词(substr
函数用于截取从指定位置开始、指定长度的子字符串,这里i + 1
是因为刚才循环结束时i
指向单词的前一个位置,所以要加 1 才是单词开始的正确位置,c
就是单词的长度),并把这个单词添加到结果字符串ans
中,同时在单词后面添加一个空格(ans += s.substr(i + 1, c) + " ";
),方便后续区分不同单词。去除最后多余的空格:当整个字符串都处理完后,通过
return ans.substr(0, ans.size() - 1);
返回最终结果。由于在添加每个单词时都额外添加了一个空格,最后结果字符串末尾会多一个空格,所以这里通过截取字符串去掉最后这个多余的空格,只返回前面正确处理好的内容,也就是完成了单词反转并且格式整理好的字符串。
string reverseWords(string s) {
int i=s.size()-1;
string ans;
while(i>=0){
int c=0;
while(i>=0&&s[i]==' ')--i;
while(i>=0&&s[i]!=' ')--i,++c;
if(c)ans+=s.substr(i+1,c)+" ";
}
return ans.substr(0,ans.size()-1);
}
二、右旋转字符串
思路:先逆序翻转,然后再翻转前N个字符串,再翻转后面的。
//逆序翻转
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int n;
string s;
cin >> n;
cin >> s;
int len = s.size(); //获取长度
reverse(s.begin(), s.end()); // 整体反转
reverse(s.begin(), s.begin() + n); // 先反转前一段,长度n
reverse(s.begin() + n, s.end()); // 再反转后一段
cout << s << endl;
}
总结
对于字符串的处理,
遍历方式
正向遍历:按顺序从开头到结尾访问字符,适用于常规顺序处理。
反向遍历:从末尾往开头遍历,便于处理与结尾相关或需逆序操作的情况。
双指针遍历:两指针依规则同步或异步移动,用于对比、处理对应字符,如判断回文。
字符操作
比较:判断字符是否为特定类型,依结果执行不同逻辑。
转换:进行大小写、字符与数值等转换,便于后续处理。
替换与删除:按需对字符替换或删除。
子字符串处理
提取:截取子字符串用于进一步分析。
查找:判断是否包含特定子字符串。
辅助数据结构
栈:用于顺序反转、暂存符合后进先出特点的内容。
队列:按先进先出顺序处理相关元素。
哈希表:高效统计字符、子字符串出现情况等。
动态规划用于存在最优子结构性质的复杂问题,通过定义状态与状态转移方程求解最优解。