C++字符串二刷

344.反转字符串

题意:

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

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

解法: 双指针法。两步:1、交换left和right指针的字符。2、left和right指针更新。

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

541. 反转字符串II

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

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

解法: 相比反转字符串多一个条件判断。

class Solution {
public:
    void reverse(string &s, int left, int right){
        while(left < right){ // 1、通过tmp交换 2、下标更新
            char tmp = s[left];
            s[left] = s[right];
            s[right] = tmp;
            left++;
            right--;
        }
        return;
    }

    string reverseStr(string s, int k) {
        for(int i = 0; i < s.size(); i += 2 * k){
            if(s.size() - i < k){
                reverse(s, i, s.size() - 1);
            }else{
                reverse(s, i, i + k -1);
            }
        }
        return s;
    }
};

剑指Offer 05.替换空格

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

解法: 双指针法。从后面往前遍历,检测到’ '就插入0、2、%。

注意:string的resize直接缩放就可以了。

class Solution {
public:
    string replaceSpace(string s) {
        int sOldSize = s.size();
        int count = 0;
        for(char c : s){
            if(c == ' ') count++;
        }
        s.resize(s.size() + 2 * count); // string的resize直接缩放就可以了
        int sNewSize = s.size();
        for(int i = sNewSize - 1, j = sOldSize - 1; i > j ; 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中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

解法: 双指针法。1、先不考虑最后一个字符串后不接空格的情况直接解,2、再想怎么插入最后一个字符串后不接空格的情况。第一步:直接根据空格分割,有空格就更新一下start为i+1。自然,更新前要先将sub string放入vector中。第二步:若不为空格,但是i为最后一个下标,则将sub string放入vector。

注意:substr(int start, int len)。

class Solution {
public:
    // 考虑两种情况:1、最后一个字符串后面没有接空格  2、最后只剩一个字符
    string reverseWords(string s) {
        // 根据空格分隔
        vector<string> vecS;
        for(int i = 0, start = 0; i < s.size(); i++){
            if(s[i] == ' '){
                if(i != start){
                    string subs = s.substr(start, i - start);
                    vecS.push_back(subs);
                }
                start = i + 1;
                continue;
            }else if(i == s.size() - 1){  // 1、最后一个字符串后面没有接空格,强行进来判断
                if(s[i] != ' '){  // 2、最后只剩一个字符(判断最后这个字符串不是空格,这样可以保证即使一个字符也可以收)
                    string subs = s.substr(start);
                    vecS.push_back(subs);
                }
            }
        }

        string result;
        for(int i = vecS.size() - 1; i >= 0; i--){
            result += vecS[i];
            if(i != 0) result += ' ';
        }
        return result;
    }
};

剑指Offer58-II.左旋转字符串

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

解法: 反转前n个字符,反转后面几个字符,反转全部字符。

reverse用法:reverse(str.begin(), str.end());

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()

题意:给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。

解法:本题是经典的KMP题目。

class Solution {
public:
    void getNext(int * next, const string & s){
        int j = -1;
        next[0] = j;
        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;
        }
    }


    int strStr(string haystack, string needle) {
        if(needle.size() == 0) return 0;
        int next[needle.size()];
        getNext(next, needle); // getNext是根据小的字符查找的

        int j = -1;
        for(int i = 0; i < haystack.size(); i++){
            while(j >= 0 && haystack[i] != needle[j + 1]){
                j = next[j];
            }
            if(haystack[i] == needle[j + 1]){
                j++;
            }
            if(j == (needle.size() - 1)){
                return (i - needle.size() + 1);
            }
        }
        return -1;
    }
};

459.重复的子字符串

题意: 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。

解法:

解法1: s+s。然后去头去尾,看看能不能在剩下的字符串中找到s。

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        string t = s + s;
        t.erase(t.begin()); t.erase(t.end() - 1); // 掐头去尾
        if (t.find(s) != std::string::npos) return true; // r
        return false;
    }
};

解法2: KMP方法。设可以找到的最小重复字串长度为x,字符串长度为n * x,字符串的最长前后缀长度相比字符串s的长度一定是少包含了一个字串x的,即n - m = 1

next数组的最后一个位置的元素+1,则可代表字符串的最长前后缀长度。若n * x % (n-m) * x,则说明存在。

(设数组长度为len,若len % (len - (next[len - 1] + 1)) == 0,则说明存在。)

class Solution {
public:
    void getNext(int * next, const string & s){
        int j = -1;
        next[0] = j;
        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;
        }
    }


    int strStr(string haystack, string needle) {
        if(needle.size() == 0) return 0;
        int next[needle.size()];
        getNext(next, needle); // getNext是根据小的字符查找的

        int j = -1;
        for(int i = 0; i < haystack.size(); i++){
            while(j >= 0 && haystack[i] != needle[j + 1]){
                j = next[j];
            }
            if(haystack[i] == needle[j + 1]){
                j++;
            }
            if(j == (needle.size() - 1)){
                return (i - needle.size() + 1);
            }
        }
        return -1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值