【LeetCode 熱題 100】438. 找到字符串中所有字母異位詞——(解法三)不定長滑動窗口+數組

Problem: 438. 找到字符串中所有字母異位詞
題目:給定兩個字符串 s 和 p,找到 s 中所有 p 的 異位詞 的子串,返回這些子串的起始索引。不考慮答案輸出的順序。

【LeetCode 熱題 100】438. 找到字符串中所有字母異位詞——(解法一)定長滑動窗口+哈希表
【LeetCode 熱題 100】438. 找到字符串中所有字母異位詞——(解法二)定長滑動窗口+數組

整體思路

這段代碼同樣用于在字符串 s 中查找所有模式串 p 的異位詞。它采用了一種更為巧妙和高效的 可變大小滑動窗口 算法。與前兩個版本(一個用 HashMap,一個用固定大小窗口的數組)相比,此版本的核心思想是維護一個“合法”的窗口,該窗口內的字符都是 p 所需要的。

算法的整體思路可以分解為以下步驟:

  1. 初始化“需求”計數器

    • 算法使用一個大小為 26 的整型數組 cnt。這個數組的含義非常關鍵:它首先被初始化為模式串 p 的字符頻率,代表著我們“需要”的字符及其數量。
    • 例如,如果 p = "aab",則 cnt['a'-'a'] 為 2,cnt['b'-'a'] 為 1。
  2. 滑動窗口的擴張與收縮

    • 算法使用 leftright 兩個指針來定義滑動窗口 [left, right]right 指針持續向右移動,以擴大窗口。
    • 擴張與“消耗”:當 right 指針掃過 s 中的一個字符 c 時,會執行 cnt[c]--。這可以理解為“消耗”掉了一個所需的字符 c
      • 如果消耗后 cnt[c]>= 0,說明這個字符是 p 所需要的,且目前窗口內該字符的數量尚未超出 p 的需求。
      • 如果消耗后 cnt[c] < 0,這說明窗口內已經包含了多余的字符 c(即超出了 p 的需求量)。
    • 收縮以維持“合法性”
      • 一旦 cnt[c] 變為負數,就觸發 while 循環。這個循環的目的是收縮窗口的左邊界 left,直到窗口再次變得“合法”。
      • 收縮時,將 left 指針指向的字符“歸還”給計數器(cnt[s.charAt(left) - 'a']++),然后將 left 右移。
      • 這個過程會一直持續,直到我們剛剛加入的那個多余字符 c 的計數 cnt[c] 不再為負。
  3. 判定與記錄結果

    • 在每一次 right 指針移動后(并可能伴隨著 left 的移動),算法會檢查當前窗口 [left, right] 的大小。
    • 如果窗口大小 right - left + 1 正好等于模式串 p 的長度 m,這意味著:
      1. 窗口內沒有多余的字符(因為 while 循環保證了所有 cnt 值都 >= 0)。
      2. 窗口的總字符數正好是 m
    • 這兩個條件同時滿足的唯一情況就是:窗口內的字符頻率與 p 完全匹配。因此,這是一個異位詞,將其起始索引 left 加入結果列表。

這種方法的精髓在于,它不強制窗口大小始終為 m,而是靈活地收縮窗口以排出“無效”字符,一旦窗口在“有效”狀態下長度恰好為 m,就找到了一個解。

完整代碼

import java.util.ArrayList;
import java.util.List;class Solution {/*** 在字符串 s 中查找 p 的所有異位詞的起始索引。* 此版本使用可變大小的滑動窗口和單個計數數組,非常高效。* @param s 主字符串 (假定只包含小寫字母)* @param p 模式字符串 (假定只包含小寫字母)* @return 一個包含所有匹配起始索引的列表*/public List<Integer> findAnagrams(String s, String p) {// ans 用于存儲結果,即所有異位詞的起始索引List<Integer> ans = new ArrayList<>();int n = s.length();int m = p.length();// 如果主串比模式串還短,直接返回空列表if (n < m) {return ans;}// cnt 數組作為字符頻率計數器。// 初始時,它存儲了模式串 p 中需要的各個字符的數量。int[] cnt = new int[26];for (char ch : p.toCharArray()) {cnt[ch - 'a']++;}// left 是滑動窗口的左邊界int left = 0;// right 是滑動窗口的右邊界,它將遍歷整個主串 sfor (int right = 0; right < n; right++) {// 獲取右邊界字符并將其映射到索引int c = s.charAt(right) - 'a';// 將該字符的所需數量減 1,表示窗口“消耗”了該字符。cnt[c]--;// 關鍵邏輯:處理窗口內字符冗余的情況。// 如果 cnt[c] < 0,說明窗口內字符 c 的數量已經超出了 p 的需求。// 此時需要從左側收縮窗口,直到 cnt[c] 恢復到 0。while (cnt[c] < 0) {// "歸還" 左邊界字符:將其在 cnt 數組中的計數加 1。cnt[s.charAt(left) - 'a']++;// 移動左邊界,縮小窗口。left++;}// 檢查窗口大小是否等于模式串的長度。// 因為 while 循環保證了窗口內沒有多余字符(所有 cnt[i] >= 0),// 如果此時窗口大小恰好為 m,那么它必然是一個異位詞。if (right - left + 1 == m) {ans.add(left);}}// 返回最終的結果列表return ans;}
}

時空復雜度

時間復雜度:O(N + M)
  1. 模式串頻率統計for (char ch : p.toCharArray()) 循環遍歷模式串 p 一次,時間復雜度為 O(M),其中 Mp 的長度。
  2. 滑動窗口遍歷
    • 外層的 for 循環由 right 指針驅動,從 0n-1,所以 right 指針總共移動了 N 次。
    • 內層的 while 循環由 left 指針驅動。雖然它在 for 循環內部,但 left 指針也只是一直向右移動,永不后退。
    • 在整個算法的生命周期中,left 指針最多從 0 移動到 n
    • 每個字符 s.charAt(i) 最多被 right 指針訪問一次,也最多被 left 指針訪問一次。因此,兩個指針的總移動次數是線性的,約為 2N
    • 所有數組操作 cnt[...]--cnt[...]++ 都是 O(1) 的。

綜合分析
總的時間復雜度是預處理 p 的時間加上兩個指針遍歷 s 的時間,即 O(M) + O(N) = O(N + M)。這是一個非常高效的線性時間復雜度。

空間復雜度:O(k) 或 O(1)
  1. 主要存儲開銷:算法只使用了一個額外的整型數組 cnt
    • 該數組的大小是 26,這是一個固定的常數,代表了字符集的大小(k=26)。它不隨輸入 sp 的長度而改變。
  2. 結果列表ans 列表用于存儲輸出,其空間不計入算法的輔助空間復雜度。
  3. 其他變量n, m, left, right, c 等都占用常數空間 O(1)。

綜合分析
算法所需的額外輔助空間主要由 cnt 數組決定。由于其大小是固定的,空間復雜度為 O(k),其中 k=26。因為 k 是一個常數,所以通常也稱其空間復雜度為 O(1)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/86636.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/86636.shtml
英文地址,請注明出處:http://en.pswp.cn/web/86636.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

求區間最大值

題目描述 給定一個長度為 N 的數列&#xff0c;和 M 次詢問&#xff0c;求出每一次詢問的區間內數字的最大值。 輸入描述 第一行包含兩個整數 N,M&#xff0c;分別表示數列的長度和詢問的個數。 第二行包含 N 個整數&#xff08;記為&#x1d44e;&#x1d456;&#xff09;&am…

調試HDMI音頻能8通道播放聲音

一、使用場景 我們是通過rk主控的hdmi接口播放音視頻給到ite68051芯片解析出8聲道數據,分別通過4路i2s的數據腳給給到fpga去解析 調試步驟: 1.根據相關手冊配置hdmi輸出,hdmi聲卡注冊,如下: hdmi0_sound: hdmi0-sound {status = "disabled";compatible = &qu…

PowerBI 柱狀圖顯示MoM銷量環比示例,以及解決相同列值時設置柱子顏色的問題

先看效果: 假設有Sales表: 1. 我們先給它新增一個計算列&#xff0c;顯示銷售日期的年月 銷售日期YYYYMM YEAR(Sales[銷售日期])*100 MONTH(Sales[銷售日期]) 2. 然后新增一個計算表&#xff0c;用于保存當前最大的銷售日期&#xff0c;和上一個月的日期 DateComparisonT…

【docker】構建時使用宿主機的代理

docker構建過程中報錯: pip 下載失敗 解決辦法:傳遞宿主機的代理 把宿主機的 HTTP_PROXY/HTTPS_PROXY 傳進去,導致容器內的 pip 依然連不上代理,下載 build-dependencies(比如 setuptools)就會失敗。 下面兩步即可解決: Docker 構建階段,127.0.0.1:7890 指向的是 容…

[Java 基礎]算法

什么是算法 程序 數據結構 算法 算法&#xff08;Algorithm&#xff09;就是解決問題的步驟&#xff0c;就像做菜的食譜一樣&#xff0c;告訴計算機一步一步如何完成任務。 例如&#xff1a; 排序算法&#xff1a;把一堆數字從小到大排列搜索算法&#xff1a;在一堆數據里…

C++理解for循環 計算題三

計算a的值 #include <iostream> using namespace std; int main() { int a0;for(int i0;i<3;i){for(int j0;j<3;j){aij;}}cout<<"a的值是 "<<a<<endl; return 0; } 計算a的值 #include <iostream> using namespace std; int …

梳理React中的fiber架構

文章目錄 產生背景核心概念工作原理工作流程優勢特點 產生背景 在React16之前使用的虛擬DOM是數組的形式&#xff0c;又因為React本身是應用級框架&#xff0c;狀態改變后并不能準確知道是哪個組件發生了改變&#xff0c;只能對整個應用進行diff協調&#xff0c;受限于虛擬DOM…

Modbus 數據模型:線圈、寄存器與功能碼詳解(二)

三、Modbus 功能碼詳解 3.1 功能碼分類與作用 Modbus 功能碼是 Modbus 通信協議中的關鍵組成部分&#xff0c;它如同一個 “指令指揮官”&#xff0c;在通信事務處理中扮演著核心角色。功能碼占用 1 個字節的空間&#xff0c;取值范圍為 1 到 255 &#xff08;0x01 - 0xFF&am…

多表連接查詢:語法、注意事項與最佳實踐

&#x1f517; 多表連接查詢&#xff1a;語法、注意事項與最佳實踐 多表連接是 SQL 的核心能力&#xff0c;用于關聯多個表的數據。以下是深度解析&#xff0c;涵蓋語法規范、性能陷阱及實戰技巧&#xff1a; &#x1f4dc; 一、多表連接語法大全 1. 顯式連接&#xff08;推薦…

使用Calibre對GDS進行數據遍歷

在芯片的GDS數據里&#xff0c;使用Calibre對數據進行處理是非常常見的操作&#xff0c;但是GDS是一種和常規設計結構不太一樣的一種數據&#xff0c;這里&#xff0c;通過這個小小的科普文章&#xff0c;一起看看怎么樣在GDS里邊做數據漫游吧&#xff01;閑言少敘&#xff0c;…

PyQtNode Editor 第二篇自定義可視化視圖

在第一篇博客中,我們已經完成了 PyQtNode Editor 的基礎環境搭建,并深入解析了自定義圖形場景QDMGraphicsScene的實現原理。那個帶有網格背景的場景就像一張空白的圖紙,現在我們要在這張圖紙上開始繪制真正的節點系統。 今天我們將聚焦于節點編輯器的核心數據結構設計,實現…

【擴歐應用】同余方程

與擴歐的聯系 在同余方程的求解過程中&#xff0c;我們通常需要將方程轉化為線性不定方程&#xff08;Diophantine 方程&#xff09;的形式&#xff0c;然后使用擴展歐幾里得算法&#xff08;Extended Euclidean Algorithm, EEA&#xff09;求解。 同余方程是怎么轉化為線性不…

結構化數據:NumPy 的結構化數組

文章目錄 結構化數據&#xff1a;NumPy 的結構化數組探索結構化數組的創建更高級的復合類型記錄數組&#xff1a;結構化數組的變體走向 Pandas 結構化數據&#xff1a;NumPy 的結構化數組 雖然我們的數據通常可以用同質數組很好地表示&#xff0c;但有時情況并非如此。本文將演…

phpcms 更換新域名更新欄目url和內容頁url無法更新解決方法

更換域名后更新欄目url和內容頁url還是無法更新為新的域名&#xff0c;手動把cache文件夾下能清除的緩存文件清除了還是不行&#xff0c;把數據庫的緩存表內容清空了還是不行&#xff0c;問題在于欄目緩存并沒有清除。 解決辦法: (1)、找到文件&#xff1a;/caches/configs/sys…

瑪哈特七輥矯平機:板材平整的精密衛士

在金屬板材加工領域&#xff0c;表面平整度是衡量產品質量的核心指標之一。無論是汽車覆蓋件、精密儀器外殼&#xff0c;還是建筑裝飾板材&#xff0c;任何彎曲、波浪或翹曲都將嚴重影響后續加工精度、產品強度及美觀度。七輥矯平機&#xff0c;憑借其獨特的輥系結構設計&#…

融合聚類與分類的退役鋰電智能分選技術:助力新能源汽車產業可持續發展

融合聚類與分類的退役鋰電智能分選技術&#xff1a;助力新能源汽車產業可持續發展 關鍵詞&#xff1a;退役鋰離子電池分選 | 聚類分類融合 | 電化學阻抗譜(EIS) | 動態時間規整(DTW) | 多模態分類模型 新能源汽車 | 電池梯次利用 | 增量學習 | 數字孿生 | 聯邦學習 | 雙流特征…

jenkins中執行python腳本導入路徑錯誤

&#x1f9fe; 問題一&#xff1a;ModuleNotFoundError: No module named jenkins &#x1f50d; 現象&#xff1a; 在本地運行正常&#xff0c;但在 Jenkins 中運行腳本時報錯&#xff0c;提示找不到 jenkins 模塊。 ? 原因分析&#xff1a; Python 默認只從當前目錄或已…

華為云Flexus+DeepSeek征文 | 華為云ModelArts Studio實戰指南:創建高效的AingDesk知識庫問答助手

華為云FlexusDeepSeek征文 | 華為云ModelArts Studio實戰指南&#xff1a;創建高效的AingDesk知識庫問答助手 前言一、ModelArts Studio介紹1. 華為云ModelArts Studio簡介2. 華為云ModelArts Studio主要特點3. 華為云ModelArts Studio主要使用場景 二、AingDesk介紹1. AingDes…

NLP基礎1_word-embedding

基于github項目&#xff1a;https://github.com/shibing624/nlp-tutorial/tree/main 自然語言處理任務 1) 簡單任務 拼寫檢查 Spell Checking 關鍵詞檢索 Keyword Search 同義詞查找 Finding Synonyms 2) 中級任務 解析來自網站、文檔等的信息 3) 復雜任務 機器翻譯 Ma…

ClickHouse系列--BalancedClickhouseDataSource實現

clickhouse-jdbc中負載均衡數據源的實現。 基本邏輯如下&#xff1a; 1.通過配置的url串&#xff0c;來切分構造url列表&#xff1b; 2.通過一個定時線程任務&#xff0c;來不斷的去ping url列表&#xff0c;來更新可用的url列表&#xff1b; 3.在可用列表中隨機返回一個可用ur…