代码随想录算法训练营第九天|151.翻转字符串里的单词、卡码网:55.右旋转字符串、28. 实现 strStr()、459.重复的子字符串

151.翻转字符串里的单词

leetcode题目链接
如果不使用辅助空间原地操作的话,算法会比较复杂一些。

分3步走:

  1. 删除额外的空格
  2. 翻转整个字符串
  3. 翻转每个单词

去除空格的操作和27. 移除元素是一样的思路,使用双指针将需要的元素挪到左指针,但是需要手动添加空格。我的逻辑是遇到非空格,除非是第一个单词,都手动添加一个空格,然后挪动一整个单词。在我的代码中,挪动完一个完整单词后,右指针会向后移动两个,不过这个并不影响结果。

class Solution {
public:
    void reverse(string& s, int start, int end) {
        int left = start, right = end;
        while (left < right) 
            swap(s[left++], s[right--]);
    }

    void removeSpace(string& s) {
        int left = 0;
        for (int right = 0; right < s.size(); right++) {
            if (s[right] != ' ') {
                if (left != 0)
                    s[left++] = ' ';
                while (right < s.size() && s[right] != ' ') 
                    s[left++] = s[right++];
            }
        }
        s.resize(left);
    }

    string reverseWords(string s) {
        removeSpace(s);
        reverse(s, 0, s.size() - 1);
        int left = 0, right = 0;
        while (left < s.size()) {
            while (s[right] != ' ' && right < s.size())
                right++;
            reverse(s, left, right - 1);
            right++;
            left = right;
        }
        return s;
    }
};

55. 右旋字符串

leetcode题目链接

  1. 将字符串整体翻转,这样后n位就到前面来了
  2. 然后将前n位和余下的局部翻转。
#include 
#include 
#include 
using namespace std;
int main() {
    int n;
    string s;
    cin >> n >> s;
    reverse(s.begin(), s.end());
    reverse(s.begin(), s.begin() + n);
    reverse(s.begin() + n, s.end());
    cout << s << endl;
}

28. 实现 strStr()

leetcode题目链接

这一题就是要匹配字符串,暴力解法是两层for循环,时间复杂度是 O ( n ∗ m ) O(n*m) O(nm)
KMP算法对此进行了优化,当模式串与字符串出现冲突时,模式串不必回退到最开始,而是根据前缀表选择回退的下标,时间复杂度为 O ( n + m ) O(n+m) O(n+m)

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

459.重复的子字符串

leetcode题目链接

移动匹配

拼接一个s+s的新字符串,去除首尾,判断是否有s子串。


class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        string t = s + s;
        t = t.substr(1, t.size() - 2);
        if (t.find(s) != std::string::npos)
            return true;
        else 
            return false;
    }
};

KMP算法

字符串的最长相等前后缀所余下的是最小子串。

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

你可能感兴趣的:(算法)