L51.【LeetCode題解】438. 找到字符串中所有字母異位詞(四種方法)

目錄

1.題目

2.分析

暴力解法

方法1:排序(超時)

方法2:哈希表(險過)

★判斷兩個哈希表是否相同算法(通用方法,必須掌握)

能相等的前提:兩個哈希表的大小相等

哈希表有迭代器,可以使用范圍for從頭到尾遍歷

提交結果

優化方法:定長滑動窗口

提交結果

使用哈希數組更快

提交結果

★★★更優化的方法:不定長滑動窗口(比定長的要快!)

提交結果


1.題目

https://leetcode.cn/problems/find-all-anagrams-in-a-string/

給定兩個字符串?s?和 p,找到?s?中所有?p?的?

?的子串,返回這些子串的起始索引。不考慮答案輸出的順序。

示例?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" 的異位詞。

提示:

  • 1 <= s.length, p.length <= 3 * 104
  • s?和?p?僅包含小寫字母

2.分析

暴力解法

大致思路:使用i遍歷字符串s,從i位置截取和p相同長度的子串(前提p.size()<=s.size(),這個要在一開始就要判斷),比較這個子串和p是否是異位詞

方法1:排序(超時)

可以先對兩個串排序,再調用operator==判斷是否相等

class Solution {
public:vector<int> findAnagrams(string s, string p){if (p.size()>s.size())return {};vector<int> ret;sort(p.begin(),p.end());for (int i = 0; i <= s.size() - p.size(); i++){string tmp=s.substr(i,p.size());sort(tmp.begin(),tmp.end());if (p==tmp)ret.push_back(i);}return ret;}
};

調用sort函數的時間復雜度是O(NlogN),過高容易超時:

方法2:哈希表(險過)

統計s的子串和p串的詞頻,記錄到哈希表中,再判斷兩個哈希表是否相同,這個時間復雜度比方法1低一點

★判斷兩個哈希表是否相同算法(通用方法,必須掌握)

雖然可以用哈希數組hash['z'+1]投機取巧(這個解法在本文的最后),但是其他題可能用不了哈希數組,因此掌握通用的方法是很有必要的

算法:

能相等的前提:兩個哈希表的大小相等
if (mp1.size() != mp2.size()) return false;
哈希表有迭代器,可以使用范圍for從頭到尾遍歷

STL的map底層實現是紅黑樹,對于for (const auto& pair : mp1),pair拿到的是mp1的紅黑樹中一個節點,到mp2中查有沒有相同的節點即可,使用find函數

find函數的查找邏輯:

cplusplus網上是這樣說的:https://legacy.cplusplus.com/reference/map/map/find/

find取得(get)指向元素的迭代器(iterator to element)

在容器中查找一個鍵值與k等價的元素,如果找到,則返回指向該元素的迭代器;否則返回指向map::end的迭代器

比較時會出現兩種情況

1.找到一個鍵值與k等價的元素,此時還不能斷定兩個節點一定相等,需要比較第二個關鍵字(pair.second)是否相等,如果不等(it->second != pair.second),返回false

2.沒找到一個鍵值與k等價的元素(it == mp2.end()),返回false

class Solution {
public:bool check(map<int,int>& mp1,map<int,int>& mp2){if (mp1.size() != mp2.size()) return false;for (const auto& pair : mp1) {auto it = mp2.find(pair.first);if (it == mp2.end() || it->second != pair.second) return false;}return true;}vector<int> findAnagrams(string s, string p){if (p.size()>s.size())return {};vector<int> ret;map<int,int> mp1;for (int i=0;i<p.size();i++)mp1[p[i]]++;for (int i = 0; i <= s.size() - p.size(); i++){map<int,int> mp2;string tmp=s.substr(i,p.size());for (int i=0;i<tmp.size();i++)mp2[tmp[i]]++;if (check(mp1,mp2))ret.push_back(i);}return ret;}
};
提交結果

優化方法:定長滑動窗口

以s = "cbaebabacd", p = "abc"為例分析:

異位詞子串首先要長度和p從串相等,對s從頭到尾遍歷即可,

在移動窗口時,注意左側元素離開哈希表,右側元素加入哈希表,當mp2[s[left]]==0時,必須刪除這個節點,否則影響哈希表的結構

class Solution {
public:bool check(map<int,int>& mp1,map<int,int>& mp2){if (mp1.size() != mp2.size()) return false;for (const auto& pair : mp1) {auto it = mp2.find(pair.first);if (it == mp2.end() || it->second != pair.second) return false;}return true;}vector<int> findAnagrams(string s, string p){if (p.size()>s.size())return {};vector<int> ret;map<int,int> mp1,mp2;for (int i=0;i<p.size();i++){mp1[p[i]]++;mp2[s[i]]++;}for (int left=0,right=p.size()-1; right<s.size();left++,right++){if (check(mp1,mp2)){ret.push_back(left);}mp2[s[left]]--;mp2[s[right+1]]++;if (mp2[s[left]]==0)mp2.erase(s[left]);}return ret;}
};

注:right+1最大為s.size(),此時mp2[s[right+1]]++;訪問到字符串的'\0'沒有越界,不影響結果?

提交結果

使用哈希數組更快

將map<int,int>改成數組,其他地方稍作修改即可

class Solution {
public:bool check(int* mp1,int* mp2){for(int i='a';i<='z';i++)if (mp1[i]!=mp2[i])return false;return true; }vector<int> findAnagrams(string s, string p){if (p.size()>s.size())return {};vector<int> ret;int mp1['z'+1]={0},mp2['z'+1]={0};for (int i=0;i<p.size();i++){mp1[p[i]]++;mp2[s[i]]++;}for (int left=0,right=p.size()-1; right<s.size();left++,right++){if (check(mp1,mp2))ret.push_back(left);mp2[s[left]]--;mp2[s[right+1]]++;}return ret;}
};
提交結果

★★★更優化的方法:不定長滑動窗口(比定長的要快!)

hash_s是字符串s的滑動窗口的哈希數組,hash_p是字符串p的的哈希數組

上面的優化的方法還可以繼續優化,引入有效字符的個數:

先讓hash_s[s[right]]++,之后判斷:

1.當hash_s[s[right]] <= hash_p[s[right]]時計入有效字符的個數count,即count++

2.一旦窗口長度大于len時,及時調整讓left++,當hash_s[s[left]] <= hash_p[s[left]]時減小有效字符的個數count,即count--

★更新結果的條件:窗口長度相等,且有效字符的個數要相等,這樣就不用像上面方法那樣遍歷mp1和mp2數組的每個元素

個數從0變成1,有效字符的個數+1,因此count++

個數從1變成0,有效字符的個數-1,因此count--

符合有效字符的個數==p串的長度,將left尾插到返回數組ret

class Solution {
public:vector<int> findAnagrams(string s, string p) {if (p.size() > s.size())return {};vector<int> ret;int len = p.size();int count = 0;int hash_s['z'+1] = {0}, hash_p['z'+1] = {0};for (int i = 0; i < p.size(); i++)hash_p[p[i]]++;for (int left = 0, right = 0; right < s.size(); right++) {hash_s[s[right]]++;if (hash_s[s[right]] <= hash_p[s[right]])count++;if (right - left + 1 > len) {if (hash_s[s[left]] <= hash_p[s[left]])count--;hash_s[s[left]]--;left++;}if (count == len)ret.push_back(left);}return ret;}
};
提交結果

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

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

相關文章

Qt模塊化架構設計教程 -- 輕松上手插件開發

概述 在軟件開發領域,隨著項目的增長和需求的變化,保持代碼的可維護性和擴展性變得尤為重要。一個有效的解決方案是采用模塊化架構,尤其是利用插件系統來增強應用的功能性和靈活性。Qt框架提供了一套強大的插件機制,可以幫助開發者輕松實現這種架構。 模塊化與插件系統 模…

深入理解 HashMap 的索引計算:右移與異或的作用

在 Java 中&#xff0c;HashMap 是一種高效的數據結構&#xff0c;它通過將鍵映射到數組中的索引位置來實現快速的插入和查找。但之前看源碼總是理解到它要hash之后散列到數組中某一個位置&#xff0c;但卻從未深究它究竟怎么散列的&#xff0c;如果不夠散那就意味著hash沖突增…

overleaf較高級的細節指令

換行命令 原來代碼是將三個矩陣表達式在同一行顯示&#xff0c;使用aligned環境&#xff08;需引入amsmath宏包&#xff0c;一般文檔導言區默認會引入&#xff09;&#xff0c;把三個矩陣的定義分別放在不同行&#xff0c;可通過\\換行。 對齊命令 &放在等號前&#xff0…

LiteLLM:統一API接口,讓多種LLM模型調用如臂使指

在人工智能迅猛發展的今天,各種大語言模型(LLM)層出不窮。對開發者而言,如何高效集成和管理這些模型成為一個棘手問題。LiteLLM應運而生,它提供了一個統一的API接口,讓開發者可以輕松調用包括OpenAI、Anthropic、Cohere等在內的多種LLM模型。本文將深入介紹LiteLLM的特性、…

Google語法整理

以下是從整理出的 Google 語法&#xff1a; site&#xff1a;指定域名&#xff0c;如 “apache site:bbs.xuegod.cn”&#xff0c;可查詢網站的收錄情況 。 inurl&#xff1a;限定在 url 中搜索&#xff0c;如 “inurl:qq.txt”&#xff0c;可搜索 url 中包含特定內容的頁面&a…

python 寫一個工作 簡單 番茄鐘

1、圖 2、需求 番茄鐘&#xff08;Pomodoro Technique&#xff09;是一種時間管理方法&#xff0c;由弗朗西斯科西里洛&#xff08;Francesco Cirillo&#xff09;在 20 世紀 80 年代創立。“Pomodoro”在意大利語中意為“番茄”&#xff0c;這個名字來源于西里洛最初使用的一個…

Compose Multiplatform iOS 穩定版發布:可用于生產環境,并支持 hotload

隨著 Compose Multiplatform 1.8.0 的發布&#xff0c;iOS 版本也引來的第一個穩定版本&#xff0c;按照官方的原話&#xff1a;「iOS Is Stable and Production-Ready」 &#xff0c;而 1.8.0 版本&#xff0c;也讓 Kotlin 和 Compose 在移動端有了完整的支持。 在 2023 年 4 …

Jenkins 服務器上安裝 Git

安裝 Git # 更新包列表 sudo apt update# 安裝 Git sudo apt install git 驗證安裝 # 檢查 Git 版本 git --version 查看所有全局配置 git config --global --list 查看特定配置項 # 查看用戶名配置 git config --global user.name# 查看郵箱配置 git config --global u…

OpenHarmony SystemUI開發——實現全局導航欄和狀態欄關閉

在實際生產中&#xff0c;進場遇到需要關閉導航欄和狀態欄的需求&#xff0c;現分享解決辦法&#xff1a; 開發環境 OpenHarmony 5.0.0r 代碼分析 思路&#xff1a; launcher本身可以關閉 導航欄&#xff08;實際是 公共事件&#xff0c;發送消息給systemUI來實控制&#x…

大模型微調終極方案:LoRA、QLoRA原理詳解與LLaMA-Factory、Xtuner實戰對比

文章目錄 一、微調概述1.1 微調步驟1.2 微調場景 二、微調方法2.1 三種方法2.2 方法對比2.3 關鍵結論 三、微調技術3.1 微調依據3.2 LoRA3.2.1 原理3.2.2 示例 3.3 QLoRA3.4 適用場景 四、微調框架4.1 LLaMA-Factory4.2 Xtuner4.3 對比 一、微調概述 微調&#xff08;Fine-tun…

單片機-STM32部分:10-2、邏輯分析儀

飛書文檔https://x509p6c8to.feishu.cn/wiki/VrdkwVzOnifH8xktu3Bcuc4Enie 安裝包如下&#xff1a;根據自己的系統選擇&#xff0c;目前這個工具只有window版本哦 安裝方法比較簡單&#xff0c;都按默認下一步即可&#xff0c;注意不要安裝到中文路徑哦。 其余部分參考飛書文檔…

uniapp-商城-48-后臺 分類數據添加修改彈窗bug

在第47章的操作中&#xff0c;涉及到分類的添加、刪除和更新功能&#xff0c;但發現uni-popup組件存在bug。該組件的函數接口錯誤導致在小程序中出現以下問題&#xff1a;1. 點擊修改肉類名稱時&#xff0c;回調顯示為空&#xff0c;并報錯“setVal is not defined”&#xff0…

STM32-ADC模數轉換器(7)

目錄 一、ADC簡介 二、逐次逼近型ADC 三、ADC基本結構圖 四、規則組的四種轉換模式 五、轉換時間 對GPIO來說&#xff0c;它只能讀取引腳的高低電平&#xff0c;使用了ADC模數轉化器之后&#xff0c;就可以對高電平和低電平之間的任意電壓進行量化&#xff0c;最終用一個變…

智能商品推薦系統技術路線圖

智能商品推薦系統技術路線圖 系統架構圖 --------------------------------------------------------------------------------------------------------------- | 用戶交互層 (Presentation Layer) …

【Docker系列】docker inspect查看容器部署位置

&#x1f49d;&#x1f49d;&#x1f49d;歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

標量/向量/矩陣/張量/范數詳解及其在機器學習中的應用

標量&#xff08;Scalar&#xff09;、向量&#xff08;Vector&#xff09;、矩陣&#xff08;Matrix&#xff09;、張量&#xff08;Tensor&#xff09;與范數&#xff08;Norm&#xff09;詳解及其在機器學習中的應用 1. 標量&#xff08;Scalar&#xff09; 定義&#xff1…

【2025年】基于電腦的jdk1.8通過idea創建springboot2.x版本(非常簡潔快速)

【2025年】基于電腦的jdk1.8通過idea創建springboot2.x版本 提示&#xff1a;幫幫志會陸續更新非常多的IT技術知識&#xff0c;希望分享的內容對您有用。本章分享的是springboot的使用。前后每一小節的內容是存在的有&#xff1a;學習and理解的關聯性。【幫幫志系列文章】&…

SierraNet協議分析使用指導[RDMA]| 如何設置 NVMe QP 端口以進行正確解碼

在解碼RoCEv2數據包&#xff08;包括TCP RDMA和RoCE RDMA&#xff09;時&#xff0c;若捕獲的跟蹤數據無法正確解碼&#xff0c;通常需要執行特定的解碼步驟。對于RoCE RDMA跟蹤數據的處理&#xff0c;分析器主要采用兩種方式獲取必要信息以實現數據包解碼&#xff1a; 首先&am…

JavaScript基礎-局部作用域

在JavaScript中&#xff0c;理解不同種類的作用域是掌握這門語言的關鍵之一。作用域決定了變量和函數的可訪問性&#xff08;即可見性和生命周期&#xff09;。與全局作用域相對應的是局部作用域&#xff0c;它限制了變量和函數只能在其定義的特定范圍內被訪問。本文將深入探討…

李沐動手深度學習(pycharm中運行筆記)——09.softmax回歸+圖像分類數據集+從零實現+簡潔實現

09.softmax回歸圖像分類數據集從零實現簡潔實現&#xff08;與課程對應&#xff09; 目錄 一、softmax回歸 1、回歸 vs 分類 2、經典分類數據集&#xff1a; 3、從回歸到分類——均方損失 4、從回歸到多類分類——無校驗比例 5、從回歸到多類分類——校驗比例 6、softmax和…