438. 找到字符串中所有字母易位詞(Python)

題目

難度:★★☆☆☆
類型:字符串

給定一個(gè)字符串 s 和一個(gè)非空字符串 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" 的字母異位詞。

解答

這道題是【題目242. 有效的字母易位詞】的進(jìn)階版,這里不僅要實(shí)現(xiàn)字母易位詞的判別功能,而且要尋找出某一個(gè)長串中所有的字母易位詞。

關(guān)于字母易位詞。首先回顧一下字母易位詞的判別條件:如果兩個(gè)字符串中每個(gè)字符出現(xiàn)的次數(shù)均相同,那么這兩個(gè)字符串互為字母易位詞,例如"aabcc"與"accba"就互為字母易位詞。技術(shù)實(shí)現(xiàn)上,我們可以通過python中collections模塊中的Counter函數(shù)得到某一個(gè)字符串中每個(gè)字符出現(xiàn)次數(shù)的統(tǒng)計(jì),如果字符串s1和s2的統(tǒng)計(jì)結(jié)果Counter(s1)==Counter(s2),那么s1和s2就互為字母易位詞。

滑動(dòng)窗口。這里,我們要在字符串p中找到字符串s的字母易位詞,可以在字符串s中構(gòu)建一個(gè)長度與p一致的滑窗,從頭到尾劃過字符串s,在滑動(dòng)的過程中,我們可以判別滑窗范圍內(nèi)的子串是否是p的字母易位詞,如果是,則將滑窗左端位置添加到結(jié)果列表中。

計(jì)數(shù)器。我們準(zhǔn)備了一個(gè)計(jì)數(shù)器字典,用于記錄滑窗中子串各個(gè)字符出現(xiàn)次數(shù),這里為了減少計(jì)算量,我們并非每次都對滑窗進(jìn)行字符統(tǒng)計(jì),而是只對計(jì)數(shù)器中新加入的字符和剛刪除的字符進(jìn)行處理。

from collections import Counter


from collections import Counter
class Solution(object):
    def findAnagrams(self, s, p):
        
        p_count = Counter(p)                    # 對字符串p中的字符進(jìn)行計(jì)數(shù)
        s_count = Counter(s[:len(p)-1])         # 對字符串s中前l(fā)en(p)個(gè)字符進(jìn)行計(jì)數(shù)
        ans = []                                # 結(jié)果列表,用于保存s中p的易位詞出現(xiàn)位置

        for i in range(len(p)-1, len(s)):       # 從p的長度開始遍歷到s的長度
            # s[i]從右邊進(jìn)入滑動(dòng)窗口
            s_count[s[i]] += 1                  # 更新字符計(jì)數(shù)器s_count中s[i]的出現(xiàn)次數(shù)
            cur_idx = i - len(p) + 1            # 滑動(dòng)窗口左端元素在s中的位置
            cur_char = s[cur_idx]               # 滑動(dòng)窗口左端元素
            
            # 易位詞判別,比較窗口中字符串s[cur_idx:i]和目標(biāo)字符串p是否互為易位詞
            if s_count == p_count:              
                ans.append(cur_idx)             # 如果是,則將滑動(dòng)窗口左端位置加入到結(jié)果列表中
                
            s_count[cur_char] -= 1              # 將滑動(dòng)窗口左端元素從窗口中彈出,更新字符計(jì)數(shù)器
            if s_count[cur_char] == 0:          # 如果彈出后計(jì)數(shù)器中出現(xiàn)次數(shù)變?yōu)榱?                del s_count[cur_char]           # 從計(jì)數(shù)器中刪除該字符
        return ans

如有疑問或建議,歡迎評(píng)論區(qū)留言~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容