關于“雙指針法“的總結

筆者這些天終于達成了只狼的全成就,甚是歡喜。然而樂極生悲,最近做了些算法題,竟沒有一道靠自己做出來。

感覺算法題常常用到“雙指針法”呢……為什么到現在我還是做不出來這些算法題……

今天就來試著總結一下它的使用場景吧。


快慢指針法

又名為“同向指針”,常見于“原地修改數組”的情況。LeetCode.283的移動零就需要通過快慢指針來實現。

題目要求將數組中所有的0移動到末尾。但是我們習慣于數組中數據前移的操作,所以我們將問題轉換為“將非零數據前移并在末尾填充0”。

而快慢指針天然適用于這種場景:快指針跳過無用數據快速遍歷,慢指針從頭到尾依次遞增方便數據覆蓋。簡單來說就是快指針的元素覆蓋慢指針的元素。

這樣一來,前移時,一個指針存放需要前移的元素(快指針),一個指針存放需要被覆蓋的位置(慢指針)。最后快指針到達終點時,慢指針未遍歷的元素數量就是快指針跳過的元素數量。

這里以LeetCode.80刪除有序數組中的重復項為例。

不同于LeetCode.26的元素只出現一次,這里需要能夠存放兩個元素。那么對于這種原地修改數組的問題,我們依舊采用前指針覆蓋后指針的策略。對于第26題,后指針作為被覆蓋的元素,其移動受制于前指針是否發現新的不重復元素。而80題的后指針移動,不光受制于元素的不重復,也受制于后指針的前面是否夠兩個重復元素,如果有,就覆蓋(始終從后指針的角度考慮,那些元素該保留,那些元素該被覆蓋)。

class?Solution?{
public:int?removeDuplicates(vector<int>& nums)?{int?x =?0;int?y =?0;while(y < nums.size()){if(y <=?1){++x;}//因為元素有序,通過x-2判斷同時保證了元素成功前移else?if(y >?1?&& nums[x-2] != nums[y]){nums[x] = nums[y];++x;}++y;}return?x;}
};

相向指針法

兩指針對向行駛,常見于“反轉元素”的情況。LeetCode.345的反轉元音字母。如果用while迭代的話,在處理完后記得讓指針繼續行駛。

相向指針法也常常會與“貪心算法”的思想結合。常常作為條件來判斷指針移動的時機。經典的是“盛水體積”問題,每次選擇最短的木板移動。因為我們確定,局部的選擇短板移動最終促成整體能夠找到體積最大的狀態(移動長板必定變小)。

這里以LeetCode.680驗證回文串為例,題目要求最多刪除一個字符,其能夠成為回文串。這種對稱的結構天然適合對向指針,只要兩邊一樣就讓兩個指針行駛。

但如果兩邊字符不一樣呢?最多刪除一次的限制,我們應該考慮怎樣的局部最優解能最終得出回文串。此時,若刪除字符后剩余的字符串是回文串即可,那最終就是回文串。

class?Solution?{
public:bool?validPalindrome(string?s)?{int?left =?0;int?right = s.size() -?1;bool?canChange =?true;while(left < right){if(s[left] == s[right]){++left;--right;}else{//兩端不一樣時,需要查看兩種刪除的情況return?check(s, left +?1, right) || check(s, left, right -?1);}}//到最后就是普通回文串的情況return?true;}//新建函數判斷普通的回文串bool?check(string?s,?int?left,?int?right){for(int?i = left, j = right; i < j; ++i, --j){if(s[i] != s[j]){return?false;}}return?true;}
};

???????但還有一種情況是需要我們先轉化之后再使用對向指針的類型。比如經典的三數之和。

如果是兩數之和的話,可以直接使用雙指針解開。按照這個思路,三數之和的話,固定一個數,那么剩余就是兩數之和等于這個數的負數的問題。就這樣繼續用雙指針。

class?Solution?{
public:vector<vector<int>>?threeSum(vector<int>& nums) {vector<vector<int>> vec;sort(nums.begin(), nums.end());for(int?i =?0; i < nums.size() -?2?&& nums[i] <=?0; i++){if(i >?0?&& nums[i] == nums[i -?1]){continue;}int?left = i +?1;int?right = nums.size() -?1;int?target = -nums[i];while(left < right){//去重if(left > i +?1?&& nums[left] == nums[left -?1]){++left;continue;}int?sum = nums[left] + nums[right];if(sum == target){vec.push_back({nums[i], nums[left], nums[right]});++left;--right;}else?if(sum < target){++left;}else{--right;}}}return?vec;}
};

???????還有LeetCode.42的接雨水問題,這類問題的輸出總是與兩端元素的變化有關系,就需要考慮使用相向指針法解決。

滑動窗口

滑動窗口是一種較為特殊的同向指針,它通過兩個指針來維護一個窗口,這個“窗口”通常是具有某種性質的連續元素或子串。

比較經典的就是無重復字符串的最長子串。前后指針從起點出發,前指針用于擴展窗口,并每次檢測窗口“無重復字符”的性質是否改變。后指針用于收縮窗口,當字符開始出現重復,則進行收縮,當性質滿足時,繼續前指針擴展。這樣一來,便可以遍歷所有無重復字符的子串。

class?Solution?{
public:int?lengthOfLongestSubstring(string s)?{int?left =?0;int?right =?0;int?length =?0;int?maxLength =?0;vector<char> chars;bool?skip =?false;while(right < s.size()){char?cur = s[right];for(auto?c : chars){if(c == cur){//刪除第一個元素chars.erase(chars.begin());++left;length = right - left;skip =?true;//這里的continue對for起作用,不對while起作用break;}}if(skip){skip =?false;continue;}chars.push_back(cur);++right;length = right - left;if(length > maxLength){maxLength = length;}}return?maxLength;}};

???????需要注意的是,for中的continue不對外部的while起作用。

現在以這道簡單題為例,寫一下滑動窗口的解法。

class?Solution?{
public:double?findMaxAverage(vector<int>& nums,?int?k)?{int?left =?0;int?right = k -?1;int?sum =?0;for(int?i =?0; i < k; i++){sum += nums[i];}int?maxSum = sum;while(right +?1?< nums.size()){int?newSum = sum - nums[left] + nums[right +?1];if(newSum > maxSum){maxSum = newSum;} ? ? ? ? ? ?sum = newSum;++left;++right;}return?(double)maxSum/k;}
};

小結

這便是雙指針的3種常見使用方式。

如有補充交流歡迎留言,我們下次再見~

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

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

相關文章

基于51單片機的智能吊燈

基于 51 單片機的智能吊燈設計與實現論文簡綱一、引言1.1 研究背景與意義闡述傳統照明設備在節能性、智能化方面的不足&#xff0c;結合智能家居產業發展趨勢&#xff0c;說明設計基于 51 單片機的智能吊燈對提升生活便利性、降低能耗的現實意義。1.2 國內外研究現狀簡要介紹當…

CF每日三題(1500-1700)

1792C 逆向思維1036D 前綴和尺取1598D 組合數學取三元組 將二元組放在坐標系中更好找到規律 1792C 思維 1500 參考題解 正難則反 注意是對一個排列進行操作&#xff0c;最后還原成1,2,…,n 每次選兩個數字很難想&#xff0c;反著想就是把1-n的排列變成所給數組的逆操作&#x…

Boost搜索引擎項目(詳細思路版)

目錄 項目相關背景 搜索引擎原理技術棧和項目環境 導入數據到自己的本地 數據去標簽與數據清洗模塊 Enumfile(src_path, &file_list)遞歸式寫入 Parsehtml(file_list, &results)去標簽 bool Parsetitle(const string& file, string* title)拆分標題 bool Pa…

AI產品經理面試寶典第69天:大模型穩定性評估與AI倫理挑戰面試題全解析

1. AI倫理與技術挑戰 1.1 問:你認為AI的最大挑戰是什么? 答:AI面臨的最大挑戰是算法偏見與模型黑箱問題。具體表現為: 數據偏見放大:訓練數據中隱含的性別、種族等偏見會被模型繼承,如招聘算法中的性別歧視案例 決策透明性缺失:深度學習模型的可解釋性不足,醫療診斷場…

【build】RDK構建系統v0.1 (持續更新。。。。)

一、 項目概述RDK構建系統是一個用于構建和定制嵌入式系統的自動化工具&#xff0c;通過簡單的命令行操作&#xff0c;您可以完成從下載依賴包、定制根文件系統、構建內核到打包鏡像的完整流程。該系統采用模塊化設計&#xff0c;提供了豐富的配置選項&#xff0c;適用于不同的…

關于RSA和AES加密

RSA非對稱加密 非對稱加密不能傳輸大數據量&#xff0c;但比對稱加密要安全&#xff0c;所以傳輸密碼一般就是用的非對稱加密 接口拿到RSA公鑰然后再加密之后傳給后端就好了 let crypt new JSEncrypt(); crypt.setPublicKey(res.message); // console.log(加密前:, data); let…

云蝠智能VoiceAgent:AI賦能售后服務場景的創新實踐

引言&#xff1a;售后服務數字化轉型的必然趨勢在數字經濟時代&#xff0c;售后服務已成為企業核心競爭力的重要組成部分。據統計&#xff0c;優質的售后服務能夠提升客戶留存率高達67%&#xff0c;同時降低客戶獲取成本約30%。然而&#xff0c;傳統售后服務模式面臨著人力成本…

C#控制臺輸入(Read()、ReadKey()和ReadLine())

下面我們來詳細講解 C# 中三種控制臺輸入方法&#xff1a;Console.Read()、Console.ReadKey() 和 Console.ReadLine() 的區別、原理、使用場景&#xff0c;并配上清晰的代碼例子和運行結果說明。? 一、三者的根本區別&#xff08;一句話總結&#xff09;方法返回值讀取方式是否…

Windows的Roaming文件夾的作用和Local/LocalLow的區別

&#x1f4c1; Roaming 文件夾的核心意義? 什么是“漫游”&#xff08;Roaming&#xff09;&#xff1f;跨設備同步&#xff1a;當用戶登錄到同一域內的不同 Windows 設備&#xff08;如公司或學校的辦公電腦&#xff09;時&#xff0c;Roaming 文件夾中的數據會自動通過網絡同…

【Java Web 快速入門】十一、Spring Boot 原理

目錄Spring Boot 原理配置優先級Bean 管理獲取 BeanBean 的作用域第三方 BeanSpring Boot 底層原理起步依賴自動配置核心原理實例說明例 1&#xff1a;自定義一個 “日志 starter”例 2&#xff1a;SpringBoot 自帶的 spring-boot-starter-web關鍵總結Spring Boot 原理 配置優…

基于Redisson的分布式鎖原理深度解析與優化實踐

基于Redisson的分布式鎖原理深度解析與優化實踐 分布式環境下&#xff0c;鎖的實現至關重要。本文將從技術背景與應用場景出發&#xff0c;結合核心原理、關鍵源碼、實際示例&#xff0c;深入剖析Redisson分布式鎖的實現機制&#xff0c;并給出性能優化建議&#xff0c;幫助后端…

室外 3DVG 基準

室外 3DVG基準&#xff08;按重要性與被引用頻率&#xff09; Talk2Car / Talk2Car-3D (2019 / 衍生) — 對象 referral&#xff08;駕駛場景&#xff09; 說明&#xff1a;最早的自然語言 → 駕駛場景對象引用數據集之一&#xff08;原 Talk2Car 是以 nuScenes 為底并提供自然…

Jenkins安裝部署(Win11)和常見配置鏡像加速

一、安裝前準備 本文使用的Jenkins Windows一鍵安裝包&#xff0c;JDK事先配置好環境變量&#xff0c;Jenkins版本&#xff1a; Jenkins下載地址&#xff1a;jenkins一鍵安裝包v2-479-1.msi資源-CSDN下載 二、Jenkins安裝部署 1、下載Jenkins &#xff0c;點擊下一步下一步…

Windows MCP.Net:革命性的 .NET Windows 桌面自動化 MCP 服務器

&#x1f4cb; 目錄 項目概述 核心技術架構 功能特性詳解 技術實現亮點 安裝與配置 實戰應用場景 代碼示例與API詳解 性能優化與最佳實踐 未來發展規劃 總結 項目概述 在人工智能快速發展的今天&#xff0c;AI 助手與操作系統的深度集成成為了一個重要趨勢。Window…

Java ArrayList的介紹及用法

十分想念順店雜可。。。ArrayList 是 Java 集合框架中最常用的類之一&#xff0c;實現了 List 接口&#xff0c;底層基于動態數組實現&#xff0c;支持動態擴容&#xff0c;相比普通數組更靈活。以下是其詳細介紹及用法&#xff1a;一、核心特性動態大小&#xff1a;無需預先指…

Docker 命令大全及使用場景總結

一、容器生命周期管理1. 創建并運行容器docker run [選項] 鏡像名 [命令]常用選項&#xff1a;-d&#xff1a;后臺運行&#xff08;detached&#xff09;-it&#xff1a;交互式終端&#xff08;如 -it ubuntu bash&#xff09;--name&#xff1a;指定容器名稱-p 主機端口:容器端…

簡單的 HTTPS 學習

簡單的 HTTPS 學習 1. 需求 現在使用的服務是HTTP調用形式&#xff0c;服務可能會有調用外圍https形式的服務&#xff0c;簡單了解了一下&#xff0c;然后寫了一個簡單的例子進行記錄。 HTTP&#xff08;超文本傳輸協議&#xff09; 是一種用于傳輸超文本的應用層協議&#…

[系統架構設計師]系統質量屬性與架構評估(八)

[系統架構設計師]系統質量屬性與架構評估&#xff08;八&#xff09; 一.軟件系統質量屬性 1.基本概念 軟件系統質量屬性&#xff1a;可測量或可測試的屬性 開發期質量屬性&#xff0c;運行期質量屬性面向架構評估的質量屬性&#xff1a;1.可用性&#xff1a; 提升策略 錯誤檢測…

【R語言】R 語言中 gsub 與正則表達式詳解(含 POSIX 與 Perl 風格實例)

R 語言中 gsub 與正則表達式詳解&#xff08;含 POSIX 與 Perl 風格實例&#xff09; 在 R 語言中&#xff0c;字符串處理是非常常見的需求&#xff0c;R 語言中的 gsub() 函數則具有字符串替換的功能。本文將通過兩個實例&#xff0c;幫助你深入理解 R 的 gsub()、POSIX 字符…

EN55035多媒體設備電磁兼容性抗干擾要求標準

EN55035 是一項由歐洲標準化委員會制定的電磁兼容性&#xff08;EMC&#xff09;標準&#xff0c;全稱為《多媒體設備的電磁兼容性要求》。該標準主要針對多媒體設備的電磁輻射和抗干擾能力進行規范&#xff0c;確保這類設備在電磁環境中能夠正常工作&#xff0c;同時不對其他設…