LeetCode系列之字符串专题

1. 字符串题目概述

https://leetcode-cn.com/tag/string/

字符串的操作可以归结为以下几类:

  • 字符串的比较、连接操作
  • 涉及子串的操作,比如前缀、后缀等
  • 字符串间的匹配操作,如KMP算法、BM算法等

2. 典型题目

2.1 翻转字符串里的单词

https://leetcode-cn.com/problems/reverse-words-in-a-string/

string reverseWords(string s) {
    trimStr(s);
    reverse(s.begin(), s.end());
    reverseEachWord(s);
    return s;
}

void trimStr(string& s) {
    if (s.empty()) return;

    bool gotFirstAlphabet = false;
    int current = 0, nspaces = 0;
    for (int i = 0; i < s.length(); i++) {
        if (s[i] == ' ') {
            if (!gotFirstAlphabet) continue;
            nspaces++;
            if (nspaces > 1) continue;
            s[current++] = s[i];
        } else {
            gotFirstAlphabet = true;
            nspaces = 0;
            s[current++] = s[i];
        }
    }
    if (current > 0 && s[current - 1] == ' ') current--;
    s.resize(current);
}

void reverseEachWord(string& s) {
    if (s.empty()) return;

    int start = -1, end = -1;
    for (int i = 0; i < s.length(); i++) {
        if (s[i] != ' ') {
            if (start < 0) start = i;
        } else {
            end = i;
            reverse(s.begin() + start, s.begin() + end);
            start = -1;
            end = -1;
        }
    }
    reverse(s.begin() + start, s.end());
}

官方解答如下:

string reverseWords(string s) {
    // 反转整个字符串
    reverse(s.begin(), s.end());

    int n = s.size();
    int idx = 0;
    for (int start = 0; start < n; ++start) {
        if (s[start] != ' ') {
            // 填一个空白字符然后将idx移动到下一个单词的开头位置
            if (idx != 0) s[idx++] = ' ';

            // 循环遍历至单词的末尾
            int end = start;
            while (end < n && s[end] != ' ') s[idx++] = s[end++];

            // 反转整个单词
            reverse(s.begin() + idx - (end - start), s.begin() + idx);

            // 更新start,去找下一个单词
            start = end;
        }
    }
    s.erase(s.begin() + idx, s.end());
    return s;
}

显得简洁不少!注意领会学习。

时间复杂度O(N),空间复杂度O(1)。

2.2 最后一个单词的长度

https://leetcode-cn.com/problems/length-of-last-word/

int lengthOfLastWord(string s) {
    reverse(s.begin(), s.end());
    int start = findFirstLetter(s);
    int length = 0;
    for (int i = start; i < s.size(); i++) {
        if (s[i] == ' ') {
            return length;
        } else {
            length++;
        }
    }
    return length;
}

int findFirstLetter(string& s) {
    int index = 0;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] != ' ') {
            index = i;
            break;
        }
    }
    return index;
}

想写得清晰易懂一些,所以把找第一个非空字符单独拆成一个函数。

时间复杂度O(N),空间复杂度O(1)。

2.3 括号生成

https://leetcode-cn.com/problems/generate-parentheses/

2.4 外观数列

https://leetcode-cn.com/problems/count-and-say/

2.5 实现strStr()

https://leetcode-cn.com/problems/implement-strstr/

2.6 最长回文子串

https://leetcode-cn.com/problems/longest-palindromic-substring/

2.7 检测大写字母

https://leetcode-cn.com/problems/detect-capital/

bool detectCapitalUse(string word) {
    std::regex reg("^[A-Z]+$|^[a-z]+$|^[A-Z][a-z]+$");
    return std::regex_match(word, reg);
}

手写检测可以通过,且性能较高。这里又尝试了一下正则表达式的解法,也不错。

正则表达式的时间复杂度是O(N),空间复杂度O(1)。

2.8 最长有效括号

https://leetcode-cn.com/problems/longest-valid-parentheses/

2.9 二进制求和

https://leetcode-cn.com/problems/add-binary/

2.10 反转字符串

https://leetcode-cn.com/problems/reverse-string/

void reverseString(vector<char>& s) {
    int head = 0;
    int tail = s.size() - 1;
    while (head < tail) {
        swap(s[head], s[tail]);
        head++;
        tail--;
    }
}

tail = s.size() - 1; 是为了让出末尾的 ‘\0’。

时间复杂度O(N),空间复杂度O(1)。

3. 总结

posted @ 2020-08-07 11:10  不写诗的诗人小安  阅读(107)  评论(0编辑  收藏  举报