找到字元串中所有字母異位詞

找到字元串中所有字母異位詞

作者:Grey

原文地址:找到字元串中所有字母異位詞

題目描述

LeetCode 438. 找到字元串中所有字母異位詞

主要思路

使用滑動窗口和欠賬表的機制,首先,將p串建立詞頻表

        int c = pStr.length;
        for (char ch : pStr) {
            map[ch - 'a']++;
        }

用於查詢s串中還欠p串的元素種類和個數是多少。總共欠的字元個數是c。

接下來建立滑動窗口,在s串中設置l和r兩個指針,先移動r,如果r位置的字元正好是p中的字元,說明這是一次有效還款,則c--,r繼續移動,如果每次都是有效還款,則c必減為0,此時,就可以收集答案了,當r - l的長度正好是p串的長度時候,則說明必須以l位置的窗口,已經判斷完畢了,接下來,可以移動l指針,開始縮窗口。如果l縮的位置正好是有效位置,則c++(因為l的舊位置已經不屬於當前窗口了)。

時間複雜度O(N)。

完整程式碼

public class LeetCode_0438_FindAllAnagramsInAString {
    // 滑動窗口 + 欠賬表
    public List<Integer> findAnagrams(String s, String p) {
        if (s == null || p == null) {
            return new ArrayList<>();
        }
        List<Integer> ans = new ArrayList<>();
        char[] str = s.toCharArray();
        char[] pStr = p.toCharArray();
        // 詞頻表
        int[] map = new int[26];
        // 窗口從[l,r)
        int l = 0;
        int r = 0;
        // 欠賬數量
        int c = pStr.length;
        for (char ch : pStr) {
            map[ch - 'a']++;
        }
        int n = str.length;
        while (r < n) {
            if (map[str[r] - 'a'] > 0) {
                // 有效還款
                c--;
            }
            map[str[r++] - 'a']--;
            if (c == 0) {
                // 收集到一個位置
                ans.add(l);
            }
            // 形成窗口
            if (r - l == pStr.length) {
                // l面臨要出窗口
                if (map[str[l] - 'a'] >= 0) {
                    // 退回去
                    c++;
                }
                map[str[l++] - 'a']++;
            }
        }
        return ans;
    }
}

類似問題

滑動窗口最大值問題

最小覆蓋子串問題

更多

演算法和數據結構筆記