代码随想录算法训练营第八天 | 344.反转字符串、541.反转字符串Ⅱ、54. 替换数字、151反转字符串中的单词、55.右旋字符串

344.反转字符串

一、题目详情

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:

输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]

示例 2:

输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

提示:

  • 1 <= s.length <= 105
  • s[i] 都是 ASCII 码表中的可打印字符

二、解题思路

        题目说要原地修改数组,额外使用O(1)的空间解决问题,第一反应是倒着来放进一个新数组,再放回去,就很麻烦。这两天也有在练习双指针,所以就用了双指针对数组的头尾进行对称位置的交换。还是蛮简单的题目。

三、解题代码

class Solution {
public:
    void reverseString(vector<char>& s) {
        int left = 0, right = s.size() - 1;
        while(left < right){
            swap(s[left],s[right]);
            left++;
            right--;
        }
    }
};

541.反转字符串Ⅱ

一、题目详情

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例 1:

输入:s = "abcdefg", k = 2
输出:"bacdfeg"

示例 2:

输入:s = "abcd", k = 2
输出:"bacd"

提示:

  • 1 <= s.length <= 104
  • s 仅由小写英文组成
  • 1 <= k <= 104

二、解题思路

        当我写了几十行看到官方只有几行的时候我人麻了。不过很少在C++里面用reverse……

三、解题代码

class Solution {
public:
    string reverseStr(string s, int k) {
        int len = s.length();
        for(int i = 0; i < len; i += 2 * k){
            reverse(s.begin()+i, s.begin() + min(i + k, len));
        }
        return s;
    }
};

54.替换数字

一、题目详情

题目描述

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。

输入描述

输入一个字符串 s,s 仅包含小写字母和数字字符。

输出描述

打印一个新的字符串,其中每个数字字符都被替换为了number

输入示例

a1b2c3

输出示例

anumberbnumbercnumber

提示信息

数据范围:
1 <= s.length < 10000。

二、解题思路

        我一开始的想法依旧很笨重:开一个新字符串,遍历原字符串,如果遇到字母就原样加入,遇到数字就+number,这样也比较好写。

        看了代码随想录的思想后是这样的:

        如果想把这道题目做到极致,就不要只用额外的辅助空间了! (不过使用Java刷题的录友,一定要使用辅助空间,因为Java里的string不能修改)

        首先扩充数组到每个数字字符替换成 "number" 之后的大小。例如 字符串 "a5b" 的长度为3,那么 将 数字字符变成字符串 "number" 之后的字符串为 "anumberb" 长度为 8。然后从后向前替换数字字符,也就是双指针法,i指向新长度的末尾,j指向旧长度的末尾。

        相对来说节省了空间,时间复杂度好像没太大变化。

三、解题代码

#include <bits/stdc++.h>
using namespace std;

int main()
{
    string s;
    string n = "number";
    cin>>s;
    int len = s.length() - 1;
    int count = s.length();
    for(int i = 0; i<s.length(); i++){
        if(s[i] >= '0' && s[i] <= '9'){
            count+=5;
        }
    }
    s.resize(count);
    count--;
    while(count >= 0 && len >= 0){
        if(s[len] >= '0' && s[len] <= '9'){
            for(int i = n .length()-1; i >= 0; i--){
                s[count]=n[i];
                count--;
            }
        }
        else{
            s[count]=s[len];
            count--;
        }
        len--;
    }
    cout<<s;
    return 0;
}

151.反转字符串中的单词

一、题目详情

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

示例 1:

输入:s = "the sky is blue"
输出:"blue is sky the"

示例 2:

输入:s = "  hello world  "
输出:"world hello"
解释:反转后的字符串中不能存在前导空格和尾随空格。

示例 3:

输入:s = "a good   example"
输出:"example good a"
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。

提示:

  • 1 <= s.length <= 104
  • s 包含英文大小写字母、数字和空格 ' '
  • s 中 至少存在一个 单词

进阶:如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1) 额外空间复杂度的 原地 解法。

二、解题思路

        我的解法:很简单地按空格把字符串拆了存在字符串数组里,然后再倒把字符串数组连上。但这个解法额外多了一个数组的空间开销。

        C++可以通过reverse函数实现O(1)的空间开销。记录一下这个方法。首先是把整个字符串倒转,这样的话单词顺序就是我们想要输出的顺序,但空格还没处理,单词内的字母也是倒着的。这时候就一个个往里塞,遇到空格不要,遇到非空格就扫描出一整个单词往里填,有一个到多个空格隔开单词,填进去的位置要么是原本的位置要么只会往前移,不会被覆盖。填完后对单词reverse一下,词内顺序也正了,然后自己给后边填一个空格,再往下找单词,直到搞定,然后就把s后面多出来的位置全部擦掉。

三、解题代码

class Solution {
public:
    string reverseWords(string s) {
        vector<string> temp;
        string ans = "";
        for(int i = 0; i < s.length(); i++){
            if(s[i]==' '){
                continue;
            }
            else{
                string st = "";
                while(s[i]!=' '&&i<s.length()){
                    st += s[i];
                    i++;
                }
                temp.push_back(st);
            }
        }

        for(int i = temp.size()-1; i > -1; i--){
            ans+=temp[i];
            if(i!=0){
                ans+=" ";
            }
            
        }
        return ans;
    }
};

O(1)的空间开销

class Solution {
public:
    string reverseWords(string s) {

        reverse(s.begin(), s.end());

        int ptr = 0;//用这个指着s要更新的格子

        for(int i = 0; i < s.length(); i++){
            if(s[i]!=' '){//这里只用考虑非空格的字符,空格字符一律跳过
                if(ptr != 0){//指着的地方不等于0证明已经有单词加进去了,手动加空格
                    s[ptr++] = ' ';//加空格
                }
                int end = i;//从第一个非空格的字符起进行扫描,得到一个单词
                while(end < s.length() && s[end] != ' '){
                    s[ptr++] = s[end++];
                }
                reverse(s.begin()+ptr-(end-i), s.begin()+ptr);//把单词倒正
                i = end;//更新到还没处理的位置
            }
            
        }

        s.erase(s.begin()+ptr,s.end());//擦掉剩下的格子

        return s;
    }
};

55.右旋字符串

一、题目详情

时间限制:1.000S  空间限制:128MB

题目描述

字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。 

例如,对于输入字符串 "abcdefg" 和整数 2,函数应该将其转换为 "fgabcde"。

输入描述

输入共包含两行,第一行为一个正整数 k,代表右旋转的位数。第二行为字符串 s,代表需要旋转的字符串。

输出描述

输出共一行,为进行了右旋转操作后的字符串。

输入示例

2
abcdefg

输出示例

fgabcde

提示信息

数据范围:
1 <= k < 10000,
1 <= s.length < 10000;

二、解题思路

        把字符串画出来观察一下,然后发现是个整体倒转再局部倒转的关系。整体倒转后就把尾巴甩到前边来了,但是这时候我们要的两部分都还是倒着的,原本后k个就变成前k个,把前k个倒正,再把第k个到结尾的串再倒正,就行了。

三、解题代码

#include <bits/stdc++.h>
using namespace std;

int main()
{
    string s;
    int k;
    cin >> k;
    cin >> s;
    reverse(s.begin(),s.end());//全部倒过来
    reverse(s.begin(),s.begin()+k);//前k个(对应原来后k个)倒过来
    reverse(s.begin()+k,s.end());//剩下的部分再倒过去
    cout<<s;
    return 0;
}
  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值