代码随想录算法训练营第八天| 344.反转字符串 541. 反转字符串II 卡码网:54.替换数字 151.翻转字符串里的单词 卡码网:55.右旋转字符串

反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

题目链接:344. 反转字符串 - 力扣(LeetCode)

关于是否用reverse函数解决问题:如果题目关键的部分直接用库函数就可以解决,建议不要使用库函数。如果库函数仅仅是 解题过程中的一小部分,并且你已经很清楚这个库函数的内部实现原理的话,可以考虑使用库函数。

但我们循环内部可以直接用一个swap函数解决问题。

class Solution {
public:
    void reverseString(vector<char>& s) {
        char tmp;
        for(int i=0;i<=(s.size()-1)/2;i++){
            tmp=s[i];
            s[i]=s[s.size()-1-i];
            s[s.size()-1-i]=tmp;
        }
    }
};

反转字符串II

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

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

题目链接:541. 反转字符串 II - 力扣(LeetCode)

这题好多坑。

  1. 不能用-1和s.length()比较,否则会进入死循环。因为s.length()返回值不是int,而是无符号数。故和-1比较时要注意。
  2. 对于“test”,test.length()和test.size()返回值都是4(无符号)。
  3. 注意reverse()函数的区间是左闭右开的,所以第二个参数要+1才能保证翻转范围正确。

     

思路:用快慢指针遍历string,同时用start记录遍历起点,每移动k次,重置起点。直到slow指针移动到string末尾,循环结束。

 

class Solution {
public:
    string reverseStr(string s, int k) {
        int end=0;
        int start=0,slow=-1,fast=-1;
        if(s.length()<k){
            reverse(s.begin(),s.end());
            return s;
        }
        while(end!=1){
            for(int i=0;i<k;i++){
                if(slow<0||slow<s.length())
                    slow++;
                else{
                    end=1;
                    break;
                }

                if(fast<0||fast<s.length()){
                    fast++;
                }
                else {
                    end=1;
                }

                if(fast<s.length()){
                    fast++;
                }
                else 
                    end=1;
            }
            if(slow<s.length())
           reverse(s.begin()+start,s.begin()+slow+1);
           else
           reverse(s.begin()+start,s.end());
            start=fast+1;
            slow=fast;
        }
        return s;
    }
};

我是**

所以当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。

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

作者:力扣官方题解
链接:https://leetcode.cn/problems/reverse-string-ii/solutions/946553/fan-zhuan-zi-fu-chuan-ii-by-leetcode-sol-ua7s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

卡码网:54.替换数字

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

题目链接:题目页面 (kamacoder.com)

思路?replace库函数的使用罢了。

#include<iostream>
using namespace std;
int main(){
    string s;
    cin>>s;
    for(int i=0;i<s.size();i++){
        if(s[i]<='9'&&s[i]>='0'){
            s.replace(i,1,"number");
        }
    }
    cout<<s;
    return 0;
}

翻转字符串里的单词

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

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

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

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

题目链接:151. 反转字符串中的单词 - 力扣(LeetCode)

思路:先遍历s,删除所有连续的空格。然后检查首尾有无空格。将s处理完之后,根据剩余空格将s分为几段存入vector中,再倒着取出来。

但这里要注意删除连续空格时,尽量不要再for循环使用erase()函数,因为其本身是O(n)级别的,嵌套之后会变成O(n^2)级别。高效的去处冗余空格应该是这样的:

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的大小即为去除多余空格后的大小。
}

注意:

  1. vector在还没有分配任何空间时还不能像数组一样用下标形式去访问vector的(v[0]也不行)!!!否则编译通过但报运行错误runtime error!(terminate called after throwing an instance of 'std::out_of_range'   )
  2. string的compare函数在结果相等时返回的是0!大于则返回1,小于返回-1。注意返回值问题。
  3. string的erase函数在删除一个元素后,不用移动下标,因为后面的字符串已经前移占用该下标了。
class Solution {
public:
    string reverseWords(string s) {
        vector<string> str={};
        for(int i=0;i<s.size()-1;i++){
            while(!s.compare(i,1," ")&&!s.compare(i+1,1," ")){    //注意cmpare返回值
                s.erase(s.begin()+i);        //之后不用功i++
                }
        }
        if(!s.compare(0,1," "))s.erase(s.begin());
        if(!s.compare(s.size()-1,1," "))s.erase(s.end()-1);
        str=split(s," ");
        string a;
        a+=str.back();
        for(int i=str.size()-2;i>=0;i--){
            a+=" "+str[i];
        }
        return a;
    }
vector<string> split(string str,string pattern)
{
int pos;
vector<string> result;
str+=pattern;//扩展字符串以方便操作
int size=str.size();
for(int i=0; i<size; i++)
{
pos=str.find(pattern,i);
if(pos<size)
{
std::string s=str.substr(i,pos-i);
result.push_back(s);
i=pos+pattern.size()-1;
}
}
return result;
}
};

另一种思路,利用双指针倒着遍历s,同时用substr来实现切割字符串,比另外写个vector存储函数简单的多。

class Solution {
public:
    string reverseWords(string s) {
        s = ' ' + s;
        int n = s.size();
        string ans;
        for (int left = n - 1, right = n; left >=0; left--) {
            if (s[left] == ' ') {
                if (left + 1 < right) {
                    ans += s.substr(left + 1, right - left - 1);
                    ans += ' ';
                }
                right = left;
            }
        }
        return ans.substr(0, ans.size() - 1);
        
    }
};

卡码网:55.右旋转字符串

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

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

题目链接:题目页面 (kamacoder.com)

思路:利用回文串思想,将原字符串改为回文串后固定位置截取即可。

#include<iostream>
using namespace std;
int main(){
    int n;
    string s;
    cin>>n>>s;
    int len=s.size();
    
    cout<<(s+s).substr(len-n,len);
    return 0;
}

 

posted @ 2024-01-31 18:55  SandaiYoung  阅读(7)  评论(0编辑  收藏  举报