C/C++ 刷题中头疼的字符串

前言

字符串可以看成是字符组成的数组。由于字符串是程序里经常需要处理的数据类型,因此有很多针对字符串处理的题目,以下是一些常见的类型。

344.反转字符串

题目描述

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

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

输入输出样例

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

题解

这里其实可以用库 reverse 直接解决,但是这里还是理解其相应的实现。反转类似于之前讲的206.链表反转

代码

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

541.反转字符串Ⅱ

题目描述

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

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

输入输出样例

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

题解

这道题目其实也是模拟,实现题目中规定的反转规则就可以了。

代码

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);
                continue;
            }
            reverse(s.begin()+i,s.begin()+s.size());
        }
        return s;
    }
};

剑指offer 05. 替换空格

题目描述

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

输入输出样例

输入:s = "We are happy."
输出:"We%20are%20happy."

题解

这道题如果想要增加难度,最好就是在原数组进行更改。所以,我们从后往前遍历。

代码

class Solution {
public:
    string replaceSpace(string s) {
        int count=0;
        int oldsize=s.size();
        for(auto ch:s){
            if(ch==' ') count++;
        }
        s.resize(s.size()+count*2);
        int newsize=s.size();
        for(int i=newsize-1,j=oldsize-1;i>=0&&j>=0;i--,j--){
            if(s[j]!=' ') s[i]=s[j];
            else{
                s[i]='0';
                s[i-1]='2';
                s[i-2]='%';
                i-=2;
            }
        }
        return s;
    }
};

151.反转字符串里的单词

题目描述

给你一个字符串 s ,逐个翻转字符串中的所有 单词 。

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

请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。

说明:

  • 输入字符串 s 可以在前面、后面或者单词间包含多余的空格。
  • 翻转后单词间应当仅用一个空格分隔。
  • 翻转后的字符串中不应包含额外的空格。

输入输出样例

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

题解

先将首尾空格去除,然后逐步记录每一个单词,利用栈的先进后出的特性进行翻转,最后输出字符串。

代码

class Solution {
public:
    string reverseWords(string s) {
        int left=0,right=s.size()-1;
        while(left<=right&&s[left]==' ') ++left;
        while(left<=right&&s[right]==' ') --right;
        stack<string> res;
        string word;
        while(left<=right){
            auto c=s[left];
            if(c!=' '){
                word+=c;
            }else if(word.size()&&c==' '){
                res.push(word);
                word="";
            }
            left++;
        }
        res.push(word);
        word="";
        while(!res.empty()){
            word+=res.top();
            res.pop();
            if (!res.empty()) word += ' ';
        }
        return word;
    }
};

剑指offer 58-Ⅱ. 左旋转字符串

题目描述

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

输入输出样例

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

题解

为了让本题更有意义,提升一下本题难度:不能申请额外空间,只能在本串上操作。

代码

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        reverse(s.begin(),s.begin()+n);
        reverse(s.begin()+n,s.end());
        reverse(s.begin(),s.end());
        return s;
    }
};

28.实现strStr()

题目描述

实现 strStr() 函数。

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。

输入输出样例

输入:haystack = "hello", needle = "ll"
输出:2

代码

先来一个简单思路的:

class Solution {
public:
    int strStr(string haystack, string needle) {
        if(needle.empty()) return 0;
        for(int i=0;i+needle.size()<=haystack.size();i++){
            int k=i,j=0;
            while(j<needle.size()){
                if(haystack[k]!=needle[j]) break;
                k++;
                j++;
            }
            if(j==needle.size()) return i;
        }
        return -1;
    }
};

KMP算法的:

class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size(), m = needle.size();
        if (m == 0) {
            return 0;
        }
        vector<int> pi(m);
        for (int i = 1, j = 0; i < m; i++) {
            while (j > 0 && needle[i] != needle[j]) {
                j = pi[j - 1];
            }
            if (needle[i] == needle[j]) {
                j++;
            }
            pi[i] = j;
        }
        for (int i = 0, j = 0; i < n; i++) {
            while (j > 0 && haystack[i] != needle[j]) {
                j = pi[j - 1];
            }
            if (haystack[i] == needle[j]) {
                j++;
            }
            if (j == m) {
                return i - m + 1;
            }
        }
        return -1;
    }
};

459.重复的子字符串

题目描述

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

输入输出样例

输入: "abab"

输出: True

解释: 可由子字符串 "ab" 重复两次构成。

代码

这也是KMP算法的题目,先来一个简单的。

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return (s+s).find(s,1)!=s.size();
    }
};

KMP算法(前缀表减一):

class Solution {
public:
    void getNext (int* next, const string& s){
        next[0] = -1;
        int j = -1;
        for(int i = 1;i < s.size(); i++){
            while(j >= 0 && s[i] != s[j+1]) {
                j = next[j];
            }
            if(s[i] == s[j+1]) {
                j++;
            }
            next[i] = j;
        }
    }
    bool repeatedSubstringPattern (string s) {
        if (s.size() == 0) {
            return false;
        }
        int next[s.size()];
        getNext(next, s);
        int len = s.size();
        if (next[len - 1] != -1 && len % (len - (next[len - 1] + 1)) == 0) {
            return true;
        }
        return false;
    }
};

参考资料:代码随想录

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值