代码随想录day10-字符串(2)

代码随想录day10-字符串(2) & 双指针总结

1、LeetCode 151 反转字符串中的所有单词

题目分析:
本题要求反转字字符串中的所有单词,并且要求我们去除多余的空格,比如连续的空格,前导空格,以及尾随空格等等。我们的第一步应该就是去除多余的空格。然后我们可以观察到,如果我们对字符串整体进行反转,那么得到肯定也可以反转每个单词,但是,单词内部的顺序也被反转了,所以还需要针对每个单词进行局部的反转,就可以得到答案。
步骤如下:

  • 去除多余的空格;
  • 整体反转;
  • 局部反转。

题目解答:

class Solution {
public:
    string reverseWords(string s) {
        // 这个题比较技巧性,先整体反转,然后再局部反转,最后可以得到最终的答案
        removeExtraSpace(s);
        reverse(s, 0, s.size() - 1);  // 整体反转
        int left = 0;
        for (int i = 0; i < s.size(); i++) {  // 局部反转
            if (s[i] == ' ') {
                reverse(s, left, i -1);
                left = i + 1;
            }
        }
        reverse(s, left, s.size() - 1);   // 反转最后一个单词
        return s;
    }

    void removeExtraSpace(string& s) {
        int index = 0;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] != ' ') s[index++] = s[i];  // 如果不是空格,就正常添加就行
            else {
                if (i > 0 && s[i - 1] != ' ') {
                    s[index++] = s[i];  // 这种可以去除重复的以及前导空格,但是有可能最后一个会是空格(如果存在尾随空格
                }
            }
        }
        if (s[index - 1] == ' ') index--;  // 单独去除
        s.resize(index);
    }

    void reverse(string& s, int start, int end) {
        for (int i = start, j = end; i < j; i++, j--) {
            swap(s[i], s[j]);
        }
    }
};

2、剑指Offer 58 左旋转字符串

题目分析:
本题的思路很简单,左旋转就是将字符串的前k个字符,放到最后面去就行了。最简单的思路就是使用一个新字符串存放前k个字符,然后遍历字符串,从k开始的后面的字符串的索引减k即可。

题目解答:

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        int len = s.length();
        if (len == 0) return "";
        if (n > len) return s;
        string str(s.begin(), s.begin() + n);
        for (int i = n; i < len; i++) s[i - n] = s[i];
        for (int i = len - n; i < len; i++) s[i] = str[i - len + n];
        return s;
    }
};

进阶:如果本题要求不开辟额外的空间,仅仅原地左旋转呢?
这样一来,本题就比较技巧性了,但是大致思路跟上面一个题是一样的,也是局部反转加整体反转。我们观察到,如果我们先反转前k个字符,再反转后面len-k个字符,最后整体反转即可。解答如下:

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;
    }
};

3、LeetCode 28 找出字符串中第一个匹配项的下标

题目分析:
本题如果运用暴力法的话,其实也是非常简单的,我们遍历haystack字符串,然后然后依次判断长为needle的字串是否等于neddle,如果是,返回当前索引。如果遍历完整个字符串都没有的话,返回-1即可。

题目解答:

class Solution {
public:
    int strStr(string haystack, string needle) {
        // 暴力法求解
        int len1 = haystack.size();
        int len2 = needle.size();
        if (len2 > len1) return -1;
        if (haystack == needle) return 0;  // 这里的条件只能是判断字符串是否相等,不能判断长度是否相等
        for (int i = 0; i < len1; i++) {
            if (haystack[i] == needle[0] && i + len2 - 1 < len1 && haystack.substr(i, len2) == needle) 
                return i;
            // 第一个条件是为了快速判断符不符合条件,可以快速筛查,如果第一个字符都不相等,没有比下去的必要了
            // 第二个为了防止越界
        }
        return -1;
     }
};

如果本题不使用暴力法,很多答案使用的都是KMP算法,这里目前还没了解,学习之后来进行补充。(3.5)

4、LeetCode 459 重复的子字符串

本题同样的也是使用KMP算法,后续进行补充。(3.5)

本章只是浅浅的了解了一下字符串部分的内容,之前的双指针法在字符串这一类型的题目里面见的很多,此外,滑动窗口的方法在字符串中也是经常使用的,以后遇到了再进行总结。

意志是独一无二的个体所拥有的、以纠正自己的自动性的力量。——劳伦斯

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值