反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s
的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
最经典的反转字符串,定义双指针,left从前往后遍历,right从后往前遍历,当相遇时停止遍历。每一次遍历交换两个指针所在元素。
class Solution {
public:
void reverseString(vector<char>& s) {
for (int i = 0, j = s.size() - 1; i < j; i++, j--)
{
char temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
};
反转字符串II
给定一个字符串 s
和一个整数 k
,从字符串开头算起,每计数至 2k
个字符,就反转这 2k
字符中的前 k
个字符。
- 如果剩余字符少于
k
个,则将剩余字符全部反转。 - 如果剩余字符小于
2k
但大于或等于k
个,则反转前k
个字符,其余字符保持原样。
此题与以往的遍历不同,通常我们将指针移动一位,而在数组或者字符串中遇到每次需要操作k个元素时,我们可以直接将指针移动k位。本题我们通过每次移动2k个位置。每轮遍历中判断剩余元素个数是否大于等于k个,如果成立,反转[i,i+k),如果不成立,反转[i,size)。代码如下:
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += 2 * k)
{
if (i + k <= s.size()) reverse(s.begin() + i, s.begin() + i + k);
else reverse(s.begin() + i, s.end());
}
return s;
}
};
替换数字
给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。
例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。
此题目时编写完整代码,包含输入输出,为ACM模式。
代码没有难点,主要是字符扩充的思路:与删除字符的双指针解法相反,当我们需要增加字符时,首先需要计算出需要扩容的元素个数。然后将快指针指向原数组的末尾,慢指针指向扩容后的数组的末尾。这样同时往前移动时,慢指针永远在快指针后面,因此快指针并不会覆盖掉慢指针的元素,当快慢指针同时遍历到开头时,完成字符到单词的替换。
#include<iostream>
using namespace std;
int main() {
string s;
int count=0;
cin >> s;
int i = s.size() - 1;
for (int k = 0; k < s.size(); k++)
{
if (s[k] >= '0' && s[k] <= '9')
{
count++;
}
}
s.resize(s.size() + count * 5);
int j = s.size() - 1;
for(;i<j;i--)
{
if (s[i] >= '0' && s[i] <= '9')//number
{
s[j--] = 'r';
s[j--] = 'e';
s[j--] = 'b';
s[j--] = 'm';
s[j--] = 'u';
s[j--] = 'n';
}
else
{
s[j--] = s[i];
}
}
cout << s;
}
反转字符串中的单词
给你一个字符串 s
,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s
中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s
中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
由于需要将单词顺序的反转,如果每次将单词存入一个单词数组然后首尾交换比较麻烦。因此我们可以先反转整个字符串,然后遇到一个单词反转一下,最后就实现了单词顺序的反转。
此题的难点在于空格的处理,思路是我们直接忽略空格,定义快慢指针,当快指针每次遇到一个单词,即if (s[j] != ' ')//遇到一个单词处理一次,如果该单词的首字母不是在开头(即下标为0的位置)我们在慢指针处增加一个空格,然后将快指针所指向的一连串字母(即一个完整单词)赋值给慢指针,条件满足应当是while (j<s.size()&&s[j] != ' ')//处理单词的一连串字母,第一个条件是为了防止越界,并且不能颠倒两个条件,应当先判断是否越界再判断是否到单词结尾。
当空格处理完毕,我们将字符串的容量减小到i(因为前面i++)个然后进行反转,然后再依次将每个单词反转。同理我们定义快慢指针,慢指针指向单词的开头,快指针指向单词的结尾(判断条件是遇到空格或者到达字符串的结尾处),然后将[慢指针,快指针)区间内的字母进行反转。第一个条件应当是防止越界的结尾判断,并且不能颠倒两个条件,应当先判断是否越界的结尾再判断是否遇到空格的结尾。
class Solution {
public:
string reverseWords(string s) {
int i=0;
for (int j=0; j < s.size(); j++)
{
if (s[j] != ' ')//遇到一个单词处理一次
{
if (i > 0) s[i++] = ' ';//除了第一个单词,其余单词前面加空格
while (j<s.size()&&s[j] != ' ')//处理单词的一连串字母
{
s[i++] = s[j++];
}
}
}//1.处理字符串的空格
s.resize(i);//由于前面s++了。因此这里直接填i而不是i+1
reverse(s.begin(),s.end());//2.反转字符串
for (int i = 0,j=0; i <= s.size(); i++)
{
if (i == s.size()||s[i] == ' ')
{
reverse(s.begin() + j, s.begin() + i);
j = i + 1;
}
}
return s;
}
};
右旋字符串
字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。
例如,对于输入字符串 "abcdefg" 和整数 2,函数应该将其转换为 "fgabcde"。
此题比较简单,直接先将整个字符串反转,然后将两个部分分开反转即可。
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
string s;
int n;
cin >>n>> s;
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin() + n);
reverse(s.begin() + n, s.end());
cout << s;
}