滑動窗口(2)——哈希表輔助的滑動窗口算法

歡迎來到博主的專欄:算法解析
博主ID:代碼小豪

文章目錄

    • leetcode438——找到字符串中所有字母異位詞
      • 題目解析
      • 算法原理
      • 題解代碼
    • leetcode30——串聯所有單詞的子串
      • 題目解析
      • 算法原理
      • 題解代碼

leetcode438——找到字符串中所有字母異位詞

題目解析

在這里插入圖片描述
異位詞是指,有相同的英文字母組成的單詞,不要求單詞中的字母順序一致。

以示例1為例:
p中的詞組是"abc"。而在s當中有"cba","bac"這兩個子串,滿足異位詞的條件,因此返回這兩個子串的起始下標位置。

如果s=“cbaebabacd”,p = “abba”。則s中存在子串"baba"滿足異位詞的條件。
在這里插入圖片描述

返回子串"baba"在s當中的起始下標位置4。

算法原理

首先,我們思考一下,如何證明子串和字符串t的是屬于字母異位詞呢?我們要找到它們的特點,即字母要對應,字母的個數要相同,比如t當中有3個a,1個b,2個c,那么子串也要滿足有3個a,1個b,2個c,不能存在更多的字母,比如d,也不能出現不同的個數,比如5個a。

那么我們可以用哈希表來完成字母與個數的映射。我們可以創建哈希表1,用來映射t中的字母。
在這里插入圖片描述
因為小寫字母一共有26位,我們可以用int [26]的數組來作為哈希表,而不是STL中的unordered_map。因為STL容器雖然功能強大,但是效率會比數組低一些。

接下來遍歷出整個s中所有大小為4的子串,并且子串中出現的字母映射到另一張哈希表2中。
在這里插入圖片描述
接下來將hash2出現的結果與hash1挨個作對比,若hash1與hash2一致,則說明該子串是字母異位詞。此時將該下標位置記錄下來。
在這里插入圖片描述
因此我們需要找到一個遍歷字符串的算法。我們觀察一下上面遍歷的結果。
在這里插入圖片描述
由于子串的長度是固定的,可以發現,如果我們從左往右遍歷出所有的子串,只需要刪除前一個元素,插入后一個元素即可(橙色為刪除的元素,藍色為插入的元素)。因此我們可以采用滑動窗口的遍歷方式(見上一篇文章,滑動窗口是一種由暴力枚舉優化而來的遍歷算法,可以將遍歷的復雜度從O(N^2)變成O(N))。

因此我們可以定義出一個left指針,和right指針,使其都指向字符串的起始位置。
在這里插入圖片描述
由于我們還使用了哈希表來輔助完成對比任務,因此我們要讓right當前指向的元素,插入哈希表中。這步操作稱為進窗口
在這里插入圖片描述

當子串的長度等于t的長度時,我們要判斷一下hash1與hash2是否相等,相等就說明子串與t構成異位詞。記錄下left的當前下標(子串的起始位置)。

由于子串需要和字符串t的大小一致(異位詞的定義)。因此我們要保持right-left+1的大小不超過t的字符串長度,在本例中,字符串t為"abab",即長度為4.因此當right-left+1大于4時,我們要讓left指向的元素,在哈希表中被刪除,該操作稱為出窗口,完成出窗口操作后,令left++,如下:
在這里插入圖片描述
無論是進窗口,還是出窗口,都有可能導致子串的長度與t的長度相等,因此無論是進窗口操作完成后,還是出窗口操作完成后,都要判斷一下hash1和hash2。

最后就是判斷hash1和hash2的方法了,我們可以通過同時遍歷hash1和hash2的方式來完成,但是這么做效率其實并不高,博主這里講解一個優化的算法,優化的方面就是簡化哈希表的判斷。

我們可以使用count來記錄當前子串中的有效字符個數。有效字符指的是當前子串符合構成t的異位詞的字符。比如t為"aacb",子串為"cccb",此時有效字符個數僅為2(因為只有"cb"是符合構成異位詞條件的字符),因此不構成異位詞。當count與t的個數相等時,此時才符合異位詞的條件。

那么如何計算count的值呢?若是hash2中記錄的該字符的計數小于等于hash1中該字符的計數。則說明該字符是一個有效字符。若是進窗口的字符是有效字符,則count++,若是出窗口的字符符合有效字符,則count–。

因此整體的運行邏輯如下:
1.進窗口并判斷需要更新有效字符
2.判斷是否要出窗口,若出窗口則要更新有效字符
3.判斷是否構成異位詞
4.right++。

題解代碼

class Solution {
public:vector<int> findAnagrams(string s, string p) {vector<int> ret;int n=p.size();int hash1[26];for(auto e:p){hash1[e-'a']++;}int hash2[26]={0};for(int left=0,right=0,count=0;right<s.size();right++){//進窗口char in=s[right];hash2[in-'a']++;if(hash2[in-'a']<=hash1[in-'a']) count++;//判斷有效字符//出窗口if(right-left+1>n){char out=s[left++];if(hash2[out-'a']<=hash1[out-'a']) count--;//判斷有效字符hash2[out-'a']--;}if(count==n) ret.push_back(left);//判斷是否為異位詞}return ret;}
};

leetcode30——串聯所有單詞的子串

題目解析

在這里插入圖片描述
這道題的難度確實符合困難,即使是博主在思路非常明確的情況下做這道題依然被許多細節給困擾一段時間。

算法原理

這道題我們可以看做是找到字符串中所有字母異位詞的plus版,為什么這么說呢?我們以示例1為例:
在這里插入圖片描述
如果我們讓words[0]視為’A’,words[1]視為’b’。未出現在words中的其他字符串等于其他字母,那么s和words會變成下面這樣:
在這里插入圖片描述
有沒有發現,這道題的解決思路和異位詞的解決思路一模一樣?沒錯,確實如此,我們一樣時創建兩個哈希表,只不過哈希表中不再是字符與計數的映射關系,而是字符串和計數的映射關系,count從有效字符的個數變成了有效字符串的個數,遍歷的方式依然是滑動窗口,這么想這道題的難度是不是從困難變成和異位詞一樣的一般了?

不過我們要注意幾個細節

細節1:字符串s有多種遍歷方式
在這里插入圖片描述
解決方法:分多次從不同的起始位置遍歷

細節2:
right和left每次移動都要跳向后多個元素,因為這次滑動窗口要遍歷的不是單個字符,而是定長的字符串

而且由于此題涉及較多的字符串操作,因此要求我們對STL庫有一定的熟練度。

題解代碼

class Solution {
public:vector<int> findSubstring(string s, vector<string>& words) {vector<int> ret;unordered_map<string,int> hash1;int len=words[0].size();for(auto& e:words){hash1[e]++;}for(int i=0;i<len;i++){//多次遍歷unordered_map<string,int> hash2;int all=0;//hash2中記錄的字符串總個數int cnt=0;//有效字符串總數for(int left=i,right=left;right+len<=s.size();right+=len){//進窗口string sub=s.substr(right,len);hash2[sub]++;all++;if(hash2[sub]<=hash1[sub]) cnt++;//出窗口if(all>words.size()){string out;out=s.substr(left,len);if(hash2[out]<=hash1[out]) cnt--;hash2[out]--;left+=len;all--;}if(cnt==words.size()) ret.push_back(left);}}return ret;}
};

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

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

相關文章

Deepseek -> 如何寫 Dockerfile

嗯&#xff0c;用戶問的是如何制作Dockerfile&#xff0c;我得先理清楚步驟。首先&#xff0c;Dockerfile的基礎結構是什么&#xff1f;應該從基礎鏡像開始&#xff0c;對吧&#xff1f;比如FROM指令。然后可能需要設置工作目錄&#xff0c;用WORKDIR。接著復制文件&#xff0c…

RabbitMQ重復消費如何解決

消息重復消費的原因 生產者重試&#xff1a;網絡波動導致生產者未收到 Broker 確認&#xff0c;重復發送消息。消費者失敗&#xff1a;消費者處理消息后未發送 ACK&#xff0c;消息重新入隊。集群故障轉移&#xff1a;主節點宕機&#xff0c;未確認消息被重新投遞。 解決方案 …

Node-RED基礎1

目錄 一、概述二、安裝三、基操四、通訊五、數據六、節點七、 應用END 一、概述 Rode-Red是什么&#xff1f; 基于Node.js的物聯網開發工具&#xff0c;做API、通訊&#xff1b;提供了一些基本的監控功能&#xff0c;可在編輯器界面中查看節點的運行狀態、消息流量等信息。通…

java登神之階之順序表

一、了解List接口 在Java中&#xff0c;List接口是一個非常重要的集合框架接口&#xff0c;它繼承自Collection接口&#xff08;Collection接口繼承Iterable接口&#xff09;。List接口定義了一個有序集合&#xff0c;允許我們存儲元素集合。并且可以根據元素的索引來訪問集合中…

redux_舊版本

reduxjs/toolkit&#xff08;RTK&#xff09;是 Redux 官方團隊推出的一個工具集&#xff0c;旨在簡化 Redux 的使用和配置。它于 2019 年 10 月 正式發布&#xff0c;此文章記錄一下redux的舊版本如何使用&#xff0c;以及引入等等。 文件目錄如下&#xff1a; 步驟 安裝依…

MySQL:SQL優化實際案例解析(持續更新)

文章目錄 一、MySQL&#xff1a;SQL優化1、時間格式化問題&#xff08;字符串&#xff09;2、in/inner join的問題 一、MySQL&#xff1a;SQL優化 1、時間格式化問題&#xff08;字符串&#xff09; -- 優化前 SELECT * FROM test_table WHERE date_format( begin_time, %Y-%…

【含文檔+PPT+源碼】基于Python的美食數據的設計與實現

項目介紹 本課程演示的是一款基于Python的美食數據分析系統&#xff0c;主要針對計算機相關專業的正在做畢設的學生與需要項目實戰練習的 Java 學習者。 包含&#xff1a;項目源碼、項目文檔、數據庫腳本、軟件工具等所有資料 帶你從零開始部署運行本套系統 該項目附帶的源碼…

vue調整表格樣式之深度修改

舉例&#xff1a; <div class"grid-item"><h3>日數據</h3><el-table :data"dailyData" v-loading"loading"><el-table-column label"銷售姓名" align"center" prop"salesName" />…

【Go每日一練】統計字符出現的次數

&#x1f47b;創作者&#xff1a;丶重明 &#x1f47b;創作時間&#xff1a;2025年3月9日 &#x1f47b;擅長領域&#xff1a;運維 目錄 1.&#x1f636;?&#x1f32b;?題目&#xff1a;統計字符出現的次數2.&#x1f636;?&#x1f32b;?代碼中可用的資源3.&#x1f636;…

uniapp在APP平臺(Android/iOS)選擇非媒體文件

TOC 背景 在我們APP開發過程中&#xff0c;經常會有這樣一個需求場景&#xff1a;從手機中選擇文件然后進行上傳&#xff0c;這些文件主要分為兩類&#xff0c;媒體文件和非媒體文件。而媒體文件選擇在APP平臺我們可以使用uni.chooseImage和uni.chooseVideo這兩個API來實現。…

【eNSP實戰】配置交換機端口安全

拓撲圖 目的&#xff1a;讓交換機端口與主機mac綁定&#xff0c;防止私接主機。 主機PC配置不展示&#xff0c;按照圖中配置即可。 開始配置之前&#xff0c;使用PC1 ping 一遍PC2、PC3、PC4、PC5&#xff0c;讓交換機mac地址表刷新一下記錄。 LSW1查看mac地址表 LSW1配置端…

卡爾曼濾波算法從理論到實踐:在STM32中的嵌入式實現

摘要&#xff1a;卡爾曼濾波&#xff08;Kalman Filter&#xff09;是傳感器數據融合領域的經典算法&#xff0c;在姿態解算、導航定位等嵌入式場景中廣泛應用。本文將從公式推導、代碼實現、參數調試三個維度深入解析卡爾曼濾波&#xff0c;并給出基于STM32硬件的完整工程案例…

Redis----大key、熱key解決方案、腦裂問題

文章中相關知識點在往期已經更新過了&#xff0c;如果有友友不理解可翻看往期內容 出現腦裂問題怎么保證集群還是高可用的 什么是腦裂問題 腦裂說的就是當我們的主節點沒有掛&#xff0c;但是因為網絡延遲較大&#xff0c;然后和主節點相連的哨兵通信較差&#xff0c;之后主…

python總結(3)

創建自定義類 終于要創建自定義類了!下面是一個簡單的示例: class Person:def set_name(self, name):self.name namedef get_name(self):return self.namedef greet(self):print("Hello, world! Im {}.".format(self.name))這個示例包含三個方法定義&#xff0c;它…

word畢業論文“et al.”替換為“等”——宏

Sub 中文參考文獻改等()中文參考文獻改等 宏Selection.Find.ClearFormattingSelection.Find.Replacement.ClearFormattingWith Selection.Find.Text "([一-龥], )et al.".Replacement.Text "\1等.".Forward True.Wrap wdFindContinue.Format False.Ma…

網絡編程-----服務器(多路復用IO 和 TCP并發模型)

一、單循環服務器模型 1. 核心特征 while(1){newfd accept();recv();close(newfd);}2. 典型應用場景 HTTP短連接服務&#xff08;早期Apache&#xff09;CGI快速處理簡單測試服務器 3. 綜合代碼 #include <stdio.h> #include <sys/types.h> /* See NO…

typora高亮方案+鼠標側鍵一鍵改色

引言 在typora里面有一個自定義的高亮, <mark></mark>>但是單一顏色就太難看了, 我使用人工智能, 搜索全網藝術家, 匯集了幾種好看的格式,并且方便大家側鍵一鍵 調用, 是不是太方便啦 ! 示例 午夜模式 春意盎然 深海藍調 石墨文檔 秋日暖陽 蜜桃宣言 使用方法 …

swift -(5) 匯編分析結構體、類的內存布局

一、結構體 在 Swift 標準庫中&#xff0c;絕大多數的公開類型都是結構體&#xff0c;而枚舉和類只占很小一部分 比如Bool、 Int、 Double、 String、 Array、 Dictionary等常見類型都是結構體 ① struct Date { ② var year: Int ③ var month: Int ④ …

從零開始學機器學習——初探分類器

首先給大家介紹一個很好用的學習地址:https://cloudstudio.net/columns 在上一節中,我們已經完成了對所有經過均衡和清洗的菜品數據的準備工作。接下來,我們將考慮使用多種算法,也就是不同的分類器,來構建模型。我們將利用這個數據集和各種分類器,基于一組特定的配料,預…

黑色RGB是什么

>好的&#xff0c;用戶現在問的是“黑色rgb是什么”。我需要先理解用戶的問題。之前用戶在使用MATLAB調整網格線顏色時&#xff0c;可能看到了默認顏色是黑色&#xff0c;或者之前我提到過默認顏色是[0.15 0.15 0.15]&#xff0c;而用戶可能現在想知道黑色的RGB值具體是什么…