反转字符串
不考虑使用vector自带的reverse,字符串可以按数组方式进行操作,创建两个指针left和right指向头字母和尾字母,在while(right>left)循环体中,交换s[left]和s[right],并更新left和right,left++,right--。算法时间复杂度为O(n),空间复杂度为O(1)。
class Solution {
public:
void reverseString(vector<char>& s) {
int left = 0;
int right = s.size()-1;
while(right>left){
swap(s[left],s[right]);
left++;
right--;
}
}
};
反转字符串II
题目不难,逻辑比较绕,但仔细读完加debug还是能做出来的,这里新创建了一个反转函数reverse,他需要传入字符串s的引用,翻转的数组左下标left和右下标right,反转函数的书写和上题相似。之后编写reverseStr,考虑有3种情况,若剩余长度包含2k时,转换前k个字符,当剩余长度不足2k个字符长度时,分两种情况,不足长度k,剩余长度全部反转,不足长度2k,反转k。代码如下。算法空间复杂度O(1),时间复杂度O(n)。
class Solution {
public:
void reverse(string &s,int left,int right){
while(right>left){
swap(s[left],s[right]);
left++;right--;
}
}
string reverseStr(string s, int k) {
int length = s.size();
int begin = 0;
while(length/(2*k)){//当length内仍存在2k个字符时
reverse(s,begin,begin+k-1);
length = length - 2*k;
begin += 2*k;//注意begin的更新
}
if(length<k){//当剩余长度不足k时
reverse(s,begin,s.size()-1);
}
else if(length<2*k){//当剩余长度大于等于k小于2k时
reverse(s,begin,begin+k-1);
}
return s;
}
};
代码随想录里是用for循环写的,我认为更简洁明了,代码贴在下面。
class Solution {
public:
void reverse(string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
swap(s[i], s[j]);
}
}
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
// 1. 每隔 2k 个字符的前 k 个字符进行反转
// 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
if (i + k <= s.size()) {
reverse(s, i, i + k - 1);
continue;
}
// 3. 剩余字符少于 k 个,则将剩余字符全部反转。
reverse(s, i, s.size() - 1);
}
return s;
}
};
while还能写的更加简练,整合逻辑,如下所示。
class Solution {
public:
string reverseStr(string s, int k) {
int n = s.size(),pos = 0;
while(pos < n){
//剩余字符串大于等于k的情况
if(pos + k < n) reverse(s.begin() + pos, s.begin() + pos + k);
//剩余字符串不足k的情况
else reverse(s.begin() + pos,s.end());
pos += 2 * k;
}
return s;
}
};
替换数字
直观思路
新创建一个字符串ans,对输入的字符串s[i]逐个进行比较,当s[i]>='a',即当前字符属于字母,ans+=s[i],否则,s[i]为数字,ans+=“number”;
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;//创建s
cin>>s;//通过键盘输入s
string ans;
int length = s.size();
for(int i = 0; i <length;i++){
if(char(s[i])>='a'){
ans+=s[i];
}
else{
ans+="number";
}
}//判断
cout<<ans;
}
算法时间复杂度O(n),空间复杂度O(1)。
双指针法
将输入的s根据其中数字的数量,将其扩容,left指向原数组的最后一位,并向前遍历,right指向新数组的最后一位,并向前添加元素。当left指向索引元素为数字,则在新数组中反向加入‘r’,'e','b','m','u','n',没加入一个元素,right--,否则在新数组中加入left指向索引的字母。
#include <iostream>
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;
}
}
反转字符串里的单词
个人思路
考虑需要反转字符串里的单词,且单词间仅保留一个空格,从尾部开始找到每个单词,将其正序加入ans字符串,并加上空格,循环结束后移除最后一个空格。
class Solution {
public:
string reverseWords(string s) {
string ans;
int length = s.size();
for(int i = length-1;i>=0;i--){
string temp = "";//创建临时string temp用于存储逆序的逆序的单词
if(s[i] == ' '){//当逆序此时结果为空时,continue
continue;
}
while(i>= 0 && s[i]!=' '){//讲逆序的逆序的单词存入temp
temp += s[i];
i--;
}
reverse(temp.begin(),temp.end());//将temp中的单词翻转为正序
ans += temp;//ans字符串拼接temp单词
ans +=' ';//拼接完加空格
}
ans.erase(ans.end()-1);//移除最后一位空格
return ans;
}
};
算法的空间复杂度为O(n),时间复杂度为O(n)
双指针法
1.利用双指针法去多余空格
2.对s进行反转
3.对s内的所有单词进行反转
class Solution {
public:
void reverse(string& s, int start, int end){ //翻转,区间写法:左闭右闭 []
for (int i = start, j = end; i < j; i++, j--) {
swap(s[i], s[j]);
}
}
void removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
int slow = 0; //整体思想参考https://programmercarl.com/0027.移除元素.html
for (int i = 0; i < s.size(); ++i) { //
if (s[i] != ' ') { //遇到非空格就处理,即删除所有空格。
if (slow != 0) s[slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
while (i < s.size() && s[i] != ' ') { //补上该单词,遇到空格说明单词结束。
s[slow++] = s[i++];
}
}
}
s.resize(slow); //slow的大小即为去除多余空格后的大小。
}
string reverseWords(string s) {
removeExtraSpaces(s); //去除多余空格,保证单词之间之只有一个空格,且字符串首尾没空格。
reverse(s, 0, s.size() - 1);
int start = 0; //removeExtraSpaces后保证第一个单词的开始下标一定是0。
for (int i = 0; i <= s.size(); ++i) {
if (i == s.size() || s[i] == ' ') { //到达空格或者串尾,说明一个单词结束。进行翻转。
reverse(s, start, i - 1); //翻转,注意是左闭右闭 []的翻转。
start = i + 1; //更新下一个单词的开始下标start
}
}
return s;
}
};
具体参考代码随想录,时间复杂度O(n),空间复杂度O(1)。
右旋转字符串
如果不考虑空间的使用,创建新的string,根据位置再排序。
#include<iostream>
#include<string>
using namespace std;
int main(){
int k;
cin>>k;
string s;
cin>>s;
string ans;
int len = s.size();
for(int i = len-k; i<len;i++){
ans += s[i];
}//len - k后的元素先加入ans
for(int j = 0; j <len - k;j++){
ans += s[j];
}//前面元素后添加入ans
cout<<ans<<endl;
}
空间复杂度O(1),时间复杂度O(n)。
考虑不申请额外空间,参考上题的双指针法的思路,对字符串先反转,后再对子串进行局部反转。
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
int k;
cin>>k;
string s;
cin>>s;
string ans;
int len = s.size();
reverse(s.begin(),s.end());
reverse(s.begin(),s.begin()+k);
reverse(s.begin()+k,s.end());
cout<<s<<endl;
}
空间复杂度O(1),时间复杂度O(n)。
291

被折叠的 条评论
为什么被折叠?



