代码随想录算法训练营第七天|344. 反转字符串,541. 反转字符串II,122. 路径加密 , 151.翻转字符串里的单词 , 剑指Offer58-II.左旋转字符串

344. 反转字符串 - 力扣(LeetCode)

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 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;
        }
    }
};

541. 反转字符串 II - 力扣(LeetCode)

给定一个字符串 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;
    }
};

LCR 122. 路径加密 - 力扣(LeetCode)

假定一段路径记作字符串 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;
    }
};

151. 反转字符串中的单词 - 力扣(LeetCode)

给你一个字符串 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;
    }
};

LCR 182. 动态口令 - 力扣(LeetCode)

某公司门禁密码使用动态口令技术。初始密码为字符串 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)这个题值得反复思考。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值