编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s
的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入:s = ["h","e","l","l","o"] 输出:["o","l","l","e","h"]
思路:直接两端元素依次交换就行,因为不能开辟新的空间。
解决:左右指针依次向中间移动,直到两个指针相遇。
代码:
class Solution {
public:
void reverseString(vector<char>& s) {
int left=0;
int right=s.size()-1;
while(left<=right){
swap(s[left],s[right]);
++left;
--right;
}
}
};
给定一个字符串 s
和一个整数 k
,从字符串开头算起,每计数至 2k
个字符,就反转这 2k
字符中的前 k
个字符。
- 如果剩余字符少于
k
个,则将剩余字符全部反转。 - 如果剩余字符小于
2k
但大于或等于k
个,则反转前k
个字符,其余字符保持原样。
示例 1:
输入:s = "abcdefg", k = 2 输出:"bacdfeg"
思路:这题只要按照题目给出的反转方式去写代码就可以。
解决:首先反转前k个元素,在比较2k之后剩余的元素个数,小于k剩下全部反转,小于2k但大于或等于k,依然反转前k个元素。这里要用到c++中库函数reverse,注意反转的起点和终点。这里有一个地方需要思考一下,如果剩余字符大于2k,应该继续反转步骤,从2k开始计数,因此循环每次增加的数应该是2k,并且要小于字符大小。
注意:以下两种情况都是反转前k个数,①2k里面前k个数反转;②剩余的数小于 2k
但大于或等于 k
个,也是反转前k个数。可以写成一条语句。
代码:
class Solution {
public:
string reverseStr(string s, int k) {
for(int i=0;i<s.size();i+=(2*k)){
if((i+k)<=s.size()){//说明剩余的数可以反转前k个
reverse(s.begin()+i,s.begin()+i+k);//反转计数点起的k个元素,这里包含了小于 2k 但大于或等于 k 个,则反转前 k 个字符这种情况
}else{//也就是剩余的数小于k
reverse(s.begin()+i,s.end());//反转剩余的数
}
}
return s;
}
};
假定一段路径记作字符串 path
,其中以 ".
" 作为分隔符。现需将路径加密,加密方法为将 path
中的分隔符替换为空格 "
",请返回加密后的字符串。
示例 1:
输入:path = "a.aef.qerf.bb" 输出:"a aef qerf bb"
思路:替换.变成空格就行。
解决:定义一个新字符串,记录替换好的字符。
代码:
class Solution {
public:
string pathEncryption(string path) {
string str;
for(int i = 0;i<path.size();i++){
path[i]=='.'?str+=' ':str+=path[i];
}
return str;
}
};
给你一个字符串 s
,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s
中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s
中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
输入:s = "the sky is blue" 输出:"blue is sky the"
示例 2:
输入:s = " hello world " 输出:"world hello" 解释:反转后的字符串中不能存在前导空格和尾随空格。
这里要考虑两个问题:①去掉多余空格,保留单词之间一个空格;②如何反转单词。
思路①:可以用快慢指针,快指针指向字母就加入慢指针,如果快指针遇到空格,慢指针就自己补充一个空格,再让快指针移动,遇到字母再加入。
解决①:一个循环让快指针移动,如果s[fast]!=' ',就s[slow]=s[fast],再移动slow和fast,s[fast]=' '停止,除了slow等于0时候,每次s[fast]!=' '时,都要先补充空格(s[slow]=' '),slow再向右移动一格,作为下次填充单词的起点。
代码:
void a(string s){//去空格
int slow=0;
for(int fast=0;fast<s.size();++fast){
if(s[fast]!=' '){
if(slow!=0) {
s[slow]=' ';//补充单词间隔的空格
slow+=1;//slow向右移动一格,作为下次填充单词的起点
}
while(fast<s.size()&&s[fast]!=' '){
s[slow]=s[fast];
slow+=1;
fast+=1;
}
}
}
s.resize(slow);//重置s的大小
}
思路②:去完空格之后,需要反转单词,但是单词内字母顺序又不反转;这种情况肯定不能一个一个单词去反转,可以先全部反转字符串,再局部反转回单词。
解决②:先反转字符串,两端指针向里缩进,依次交换就可以;再局部反转回单词,从第一个字母开始到空格前一个字母,就是要反转的单词,再移动起点继续反转单词。
代码:
int start=0;//每次单词反转起点
for(int end=0;end<=s.size();++end){
if(s[end]==' '||end==s.size()){//遇到空格或者字符串末尾说明可以进行当前单词的局部反转
b(s, start, end - 1);
start=end+1;//局部反转起点更新
}
}
return s;
完整代码:
class Solution {
public:
void a(string& s){//去空格
int slow=0;
for(int fast=0;fast<s.size();++fast){
if(s[fast]!=' '){
if(slow!=0) {
s[slow]=' ';//补充单词间隔的空格
slow+=1;
}
while(fast<s.size()&&s[fast]!=' '){
s[slow]=s[fast];
slow+=1;
fast+=1;
}
}
}
s.resize(slow);//重置s的大小
}
void b(string& s,int start,int end){//反转
for(int i=start,j=end;i<j;i++,j--){
swap(s[i],s[j]);
}
}
string reverseWords(string s) {
a(s);
b(s,0,s.size()-1);
int start=0;//每次单词反转起点
for(int end=0;end<=s.size();++end){
if(s[end]==' '||end==s.size()){//遇到空格或者字符串末尾说明可以进行当前单词的局部反转
b(s, start, end - 1);
start=end+1;//局部反转起点更新
}
}
return s;
}
};
某公司门禁密码使用动态口令技术。初始密码为字符串 password
,密码更新均遵循以下步骤:
- 设定一个正整数目标值
target
- 将
password
前target
个字符按原顺序移动至字符串末尾
请返回更新后的密码字符串。
示例 1:
输入: password = "s3cur1tyC0d3", target = 4 输出: "r1tyC0d3s3cu"
示例 2:
输入: password = "lrloseumgh", target = 6 输出: "umghlrlose"
这里方法有很多种,练习一下反转字符串来解决
思路:可以通过局部反转+整体反转
解决:①反转区间为前n的子串;②反转区间为n到末尾的子串;③反转整个字符串
代码:(c++就是快啊)
class Solution {
public:
string dynamicPassword(string password, int target) {
reverse(password.begin(), password.begin() + target);
reverse(password.begin() + target, password.end());
reverse(password.begin(), password.end());
return password;
}
};
收获:局部反转和整体反转的顺序不同用于处理不同情况,同时复习了一下双指针151. 反转字符串中的单词 - 力扣(LeetCode)这个题值得反复思考。