LeetCode - 438. 找到字符串中所有字母异位词

描述

给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。

字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:

字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序。
示例 1:

输入:
s: "cbaebabacd" p: "abc"

输出:
[0, 6]

解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。
 示例 2:

输入:
s: "abab" p: "ab"

输出:
[0, 1, 2]

解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的字母异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的字母异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的字母异位词。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/
 

求解

    class Solution {
    public:
        // 方法一,暴力解法,以每个字符起点开始判断, 时间复杂度O(m * n),需要额外的空间复杂度
        // 低效率通过, 1300ms
        vector<int> findAnagrams_1e(string s, string p) {
            const int n = s.size();
            const int m = p.size();
            vector<int> res;
            for (int i = 0; i <= n - m; ++i) {
                if (isAnagrams(p, s, i, i + m)) {
                    res.emplace_back(i);
                }
            }
            return res;
        }

        // 方法二,暴力解法优化,以每个字符起点开始判断, 时间复杂度O(m * n),需要额外的空间复杂度
        // 低效率通过, 850ms
        vector<int> findAnagrams_2e(string s, string p) {
            const int n = s.size();
            const int m = p.size();
            vector<int> res;
            bool preIsAnagrams = false;
            for (int i = 0; i <= n - m; ++i) {
                if (preIsAnagrams && s[i - 1] == s[i + m - 1]) {
                    // 如果发现前一个满足条件,即s[i-1....i-1+m)符合条件
                    // 则只需要判断s[i-1] 是否等于 s[i+m-1],即递增中去掉的那个字符和新加入的字符是否一致,一致则同样满足条件
                    res.emplace_back(i);
                    preIsAnagrams = true;
                    continue;
                }
                if (isAnagrams(p, s, i, i + m)) {
                    res.emplace_back(i);
                    preIsAnagrams = true;
                    continue;
                }
                preIsAnagrams = false;
            }
            return res;
        }

        // 方法三,双指针滑动窗口
        vector<int> findAnagrams(string s, string p) {
            const int n = s.size();
            const int m = p.size();
            int record[126]{0};
            for (char &c : p) {
                ++record[c];
            }

            int l = 0, r = 0, num = 0;
            vector<int> res;
            while (r < n) {
                if (record[s[r]] > 0) {
                    ++num;
                }
                --record[s[r]];
                ++r;

                while (num == m) {
                    if (r - l == m) {
                        res.emplace_back(l);
                    }
                    if (record[s[l]] == 0) {
                        --num;
                    }
                    ++record[s[l]];
                    ++l;
                }
            }
            return res;
        }

    private:
        /*!
         *
         * @param p 被匹配字符串
         * @param s 待匹配字符串
         * @param is 起点,相当于begin
         * @param ie 终点, 相等于end
         * @return 返回是否是异位匹配
         */
        bool isAnagrams(const std::string_view p, const std::string_view s, int is, int ie) {
            int pattern[26]{0};
            for (const auto &c : p) {
                ++pattern[c - 'a'];
            }
            for (int i = is; i < ie; ++i) {
                --pattern[s[i] - 'a'];
            }
            for (const int &num : pattern) {
                if (num != 0) {
                    return false;
                }
            }
            return true;
        }
    };

猜你喜欢

转载自blog.csdn.net/u010323563/article/details/112920002