優選算法 --(雙指針算法 1~8)

引言:此專欄為記錄算法學習,本專題作為算法學習的第一部分,優選算法專題共計100題,分為不同小模塊進行,算法學習需堅持積累,時代不會辜負長期主義者,僅以此句,與君共勉。

講解算法分為三個步驟:(1) 題目分析 (2)算法原理 (3)代碼編寫

下面的所有題目講解都會以上述三個步驟開展


1. 移動零? ? ?283. 移動零 - 力扣(LeetCode)

(1) 題目分析:

給定一個數組 nums,編寫一個函數將所有 0 移動到數組的末尾,同時保持非零元素的相對順序。
請注意?,必須在不復制數組的情況下原地對數組進行操作。?
示例 1:
輸入: nums = [0,1,0,3,12]
輸出: [1,3,12,0,0]
示例 2:
輸入: nums = [0]
輸出: [0]?
提示:
? 1 <= nums.length <= 104
? -231?<= nums[i] <= 231?- 1

原地操作,將所有0移動到數組右側

示例 :nums = [0,1,0,3,1,2]? ? ---> [1,3,1,2,0,0]

(2) 算法原理:(快排的思想:數組劃分區間 - 數組分兩塊)

雙指針算法 -- 利用數組下標來充當指針?(這里我們定義兩個指針? ?cur , dest)
兩個指針的作用:
cur : 從左往右掃描數組,遍歷數組
dest:? 已處理的區間內,非零元素的最后一個位置

如何做到:

1.cur 遇到0元素,cur++

2,遇到非0元素,swap(dest+1,cur);

dest++ ,cur++;

(3)代碼編寫

這里注意一下dest使用的是前置++還是后置++取決于dest的起始位置

class Solution {
public:void moveZeroes(vector<int>& nums) {for(int cur = 0, dest = 0; cur < nums.size(); cur++)if(nums[cur]){swap(nums[dest++], nums[cur]); } }
};
class Solution {
public:void moveZeroes(vector<int>& nums) {for(int cur = 0, dest = -1; cur < nums.size(); cur++)if(nums[cur]){swap(nums[++dest], nums[cur]); } }
};
這個?法是往后我們學習「快排算法」的時候,「數據劃分」過程的重要?步。如果將快排算法拆 解的話,這?段?代碼就是實現快排算法的「核?步驟」。

2. 復寫零? ? ?1089. 復寫零 - 力扣(LeetCode)

(1)題目分析?

給你一個長度固定的整數數組?arr?,請你將該數組中出現的每個零都復寫一遍,并將其余的元素向右平移。

注意:請不要在超過該數組長度的位置寫入元素。請對輸入的數組?就地?進行上述修改,不要從函數返回任何東西。

示例 1:

輸入:arr = [1,0,2,3,0,4,5,0]
輸出:[1,0,0,2,3,0,0,4]
解釋:調用函數后,輸入的數組將被修改為:[1,0,0,2,3,0,0,4]

示例 2:

輸入:arr = [1,2,3]
輸出:[1,2,3]
解釋:調用函數后,輸入的數組將被修改為:[1,2,3]

這里我們要注意的問題是數組的長度是固定的,要復寫0,原數組里可能會有數據就不存在了,所以我們可以先找到復寫完的最后一個位置的元素,再從前往后完成復寫操作

(2)算法原理?

如果從前向后進行原地復寫操作的話,由于0的復寫操作,導致沒有復寫的數被覆蓋掉,因此我們選擇從后往前的復寫策略。

但是從后向前復寫的時候,我們需要找到最后一個復寫的數,大致分為兩步:

1. 先找到最后一個復寫的數

2.然后從后面向前進行復寫操作

流程:

先根據“異地”操作,然后優化成雙指針的“就地”操作

a. 先找到最后一個”復寫“的數:

? ? 1.先判斷cur位置的值

? ? 2.決dest移動兩步還是一步

? ? 3.判斷一下dest是否已經到結束為止

? ? 4.cur++

b.處理一下邊界情況

? ? n-1 ---> 0?

? ? cur?--;

? ? dest?-= 2;

c.從后向前完成復寫操作

示意圖:

(3)代碼編寫?

class Solution
{
public:void duplicateZeros(vector<int>& arr) {// 1. 先找到最后?個數int cur = 0, dest = -1, n = arr.size();while(cur < n){if(arr[cur]) dest++;else dest += 2;if(dest >= n - 1) break;cur++;}// 2. 處理?下邊界情況if(dest == n){arr[n - 1] = 0;cur--; dest -=2;}// 3. 從后向前完成復寫操作while(cur >= 0){if(arr[cur]) arr[dest--] = arr[cur--];else{arr[dest--] = 0;arr[dest--] = 0;cur--;}}}
};
class Solution {
public:void duplicateZeros(vector<int>& arr) {int n = arr.size();int i = 0, j = 0;// 第一遍掃描:計算復制后的新長度while (j < n) {if (arr[i] == 0) j++;i++;j++;}// 回退指針準備復制i--;j--;// 第二遍掃描:從后向前復制元素while (i >= 0) {if (j < n) arr[j] = arr[i];if (arr[i] == 0) {j--;if (j < n) arr[j] = 0;}i--;j--;}}
};

3. 快樂數? ?? ? 202. 快樂數 - 力扣(LeetCode)

(1)題目分析

編寫一個算法來判斷一個數?n?是不是快樂數。

「快樂數」?定義為:

  • 對于一個正整數,每一次將該數替換為它每個位置上的數字的平方和。
  • 然后重復這個過程直到這個數變為 1,也可能是?無限循環?但始終變不到 1。
  • 如果這個過程?結果為?1,那么這個數就是快樂數。

如果?n?是?快樂數?就返回?true?;不是,則返回?false?。

示例 1:

輸入:n = 19
輸出:true
解釋:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

輸入:n = 2
輸出:false

(2)算法原理

詳解:Leet code每日一題-CSDN博客

(3)代碼編寫?

class Solution {
public:int squre_sum(int n){int sum = 0;while(n){int t = n %10;sum += t*t;n /= 10;}return sum;}bool isHappy(int n) {int slow = n,fast = squre_sum(n); while(slow != fast){slow = squre_sum(slow);fast = squre_sum(squre_sum(fast));}return slow == 1;} 
};

?4. 盛最多水的類型??? ? 11. 盛最多水的容器 - 力扣(LeetCode)

(1)題目分析?

給定一個長度為?n?的整數數組?height?。有?n?條垂線,第?i?條線的兩個端點是?(i, 0)?和?(i, height[i])?。

找出其中的兩條線,使得它們與?x?軸共同構成的容器可以容納最多的水。

返回容器可以儲存的最大水量。

說明:你不能傾斜容器。

示例 1:

輸入:[1,8,6,2,5,4,8,3,7]
輸出:49 
解釋:圖中垂直線代表輸入數組 [1,8,6,2,5,4,8,3,7]。在此情況下,容器能夠容納水(表示為藍色部分)的最大值為?49。

示例 2:

輸入:height = [1,1]
輸出:1

(2)算法原理?

Leet code 每日一題-CSDN博客

(3)代碼編寫?

class Solution {
public:int maxArea(vector<int>& height){int left = 0,right = height.size()-1,ret = 0;while(left < right){int v = min(height[left] , height[right])*(right - left);ret = max(ret , v);if(height[left] < height[right]) left++;else right--;}return ret;}
};


5.有效三角形的個數? ? ?611. 有效三角形的個數 - 力扣(LeetCode)

1)題目分析?

給定一個包含非負整數的數組?nums?,返回其中可以組成三角形三條邊的三元組個數。

示例 1:

輸入: nums = [2,2,3,4]

輸出: 3

解釋:

有效的組合是: 2,3,4 (使用第一個 2)

2,3,4 (使用第二個 2) 2,2,3

示例 2:

輸入: nums = [4,2,3,4]

輸出: 4

(2)算法原理?

Leet code 每日一題-CSDN博客

(3)代碼編寫???

class Solution {
public:int triangleNumber(vector<int>& nums) {sort(nums.begin(),nums.end());int ret = 0,n = nums.size();for(int i = n-1;i>=2;i--){int left = 0, right = i -1;while(left < right){if(nums[left] +nums[right] > nums[i]){ret += right -left;right--;}else{left++;}}}return ret;}        
};


6.和為S的兩個數LCR 179. 查找總價格為目標值的兩個商品 - 力扣(LeetCode)

(1)題目分析?

購物車內的商品價格按照升序記錄于數組?price。請在購物車中找到兩個商品的價格總和剛好是?target。若存在多種情況,返回任一結果即可。

示例 1:

輸入:price = [3, 9, 12, 15], target = 18
輸出:[3,15] 或者 [15,3]

示例 2:

輸入:price = [8, 21, 27, 34, 52, 66], target = 61
輸出:[27,34] 或者 [34,27]

(2)算法原理?

解法?(暴?解法,會超時):
算法思路:
兩層 for 循環列出所有兩個數字的組合,判斷是否等于?標值。
算法流程:
兩層 for 循環:
?
外層 for 循環依次枚舉第?個數 a
?
內層 for 循環依次枚舉第?個數 b ,讓它與 a 匹配;
ps :這?有個魔?細節:我們挑選第?個數的時候,可以不從第?個數開始選,因為 a
?的數我們都已經在之前考慮過了;因此,我們可以從 a 往后的數開始列舉。
?
然后將挑選的兩個數相加,判斷是否符和目標值
. 解法?(雙指針 - 對撞指針):
注意到本題是升序的數組,因此可以?「對撞指針」優化時間復雜度。
算法流程(附帶算法分析,為什么可以使?對撞指針):
a. 初始化 left right 分別指向數組的左右兩端(這?不是我們理解的指針,?是數組的下
標)
b. left < right 的時候,?直循環
i. nums[left] + nums[right] == target 時,說明找到結果,記錄結果,并且
返回;
ii. nums[left] + nums[right] < target 時:
?
對于 nums[left] ??,此時 nums[right] 相當于是 nums[left] 能碰到的
最?值(別忘了,這?是升序數組哈~)。如果此時不符合要求,說明在這個數組??,
沒有別的數符合 nums[left] 的要求了(最?的數都滿?不了你,你已經沒救了)。
因此,我們可以?膽舍去這個數,讓 left++ ,去?較下?組數據;
?
那對于 nums[right] ??,由于此時兩數之和是?于?標值的, nums[right]
還可以選擇? nums[left] ?的值繼續努?達到?標值,因此 right 指針我們按
兵不動;
iii. nums[left] + nums[right] > target 時,同理我們可以舍去
nums[right] (最?的數都滿?不了你,你也沒救了)。讓 right-- ,繼續?較下?
組數據,? left 指針不變(因為他還是可以去匹配? nums[right] 更?的數的)。

(3)代碼編寫??

class Solution
{
public:vector<int> twoSum(vector<int>& nums, int target){int left = 0, right = nums.size() - 1;while(left < right){int sum = nums[left] + nums[right];if(sum > target) right--;else if(sum < target) left++;else return {nums[left], nums[right]};}// 照顧編譯器return {-4941, -1};??????? }
};


7. 三數之和?15. 三數之和 - 力扣(LeetCode)

(1)題目分析?

給你一個整數數組?nums?,判斷是否存在三元組?[nums[i], nums[j], nums[k]]?滿足?i != ji != k?且?j != k?,同時還滿足?nums[i] + nums[j] + nums[k] == 0?。請你返回所有和為?0?且不重復的三元組。

注意:答案中不可以包含重復的三元組。

示例 1:

輸入:nums = [-1,0,1,2,-1,-4]
輸出:[[-1,-1,2],[-1,0,1]]
解釋:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元組是 [-1,0,1] 和 [-1,-1,2] 。
注意,輸出的順序和三元組的順序并不重要。

示例 2:

輸入:nums = [0,1,1]
輸出:[]
解釋:唯一可能的三元組和不為 0 。

示例 3:

輸入:nums = [0,0,0]
輸出:[[0,0,0]]
解釋:唯一可能的三元組和為 0 。

(2)算法原理?

解法(排序+雙指針):

算法思路:
本題與兩數之和類似,是?常經典的?試題。
與兩數之和稍微不同的是,題?中要求找到所有「不重復」的三元組。那我們可以利?在兩數之和
那??的雙指針思想,來對我們的暴?枚舉做優化:
i. 先排序;
ii. 然后固定?個數 a
iii. 在這個數后?的區間內,使?「雙指針算法」快速找到兩個數之和等于 -a 即可。
但是要注意的是,這道題??需要有「去重」操作~
i. 找到?個結果之后, left right 指針要「跳過重復」的元素;
ii. 當使?完?次雙指針算法之后,固定的 a 也要「跳過重復」的元素。

3)代碼編寫

class Solution
{
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> ret;// 1. 排序sort(nums.begin(), nums.end());// 2. 利?雙指針解決問題int n = nums.size();for(int i = 0; i < n; ) // 固定數 a{if(nums[i] > 0) break; // ?優化int left = i + 1, right = n - 1, target = -nums[i];while(left < right){int sum = nums[left] + nums[right];if(sum > target) right--;else if(sum < target) left++;else{ret.push_back({nums[i], nums[left], nums[right]});left++, right--;// 去重操作 left 和 rightwhile(left < right && nums[left] == nums[left - 1]) left++;while(left < right && nums[right] == nums[right + 1]) 
right--;}}// 去重 i i++;while(i < n && nums[i] == nums[i - 1]) i++;}return ret;}
};


8.四數之和?18. 四數之和 - 力扣(LeetCode)

(1)題目分析?

給你一個由?n?個整數組成的數組?nums?,和一個目標值?target?。請你找出并返回滿足下述全部條件且不重復的四元組?[nums[a], nums[b], nums[c], nums[d]]?(若兩個四元組元素一一對應,則認為兩個四元組重復):

  • 0 <= a, b, c, d?< n
  • abc?和?d?互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按?任意順序?返回答案 。

示例 1:

輸入:nums = [1,0,-1,0,-2,2], target = 0
輸出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

輸入:nums = [2,2,2,2,2], target = 8
輸出:[[2,2,2,2]]

(2)算法原理?

.解法(排序 + 雙指針)
算法思路:
a. 依次固定?個數 a
b. 在這個數 a 的后?區間上,利?「三數之和」找到三個數,使這三個數的和等于 target
- a 即可

(3)代碼編寫??

class Solution
{
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> ret;// 1. 排序sort(nums.begin(), nums.end());// 2. 利?雙指針解決問題int n = nums.size();for(int i = 0; i < n; ) // 固定數 a{// 利? 三數之和for(int j = i + 1; j < n; ) // 固定數 b{// 雙指針int left = j + 1, right = n - 1;long long aim = (long long)target - nums[i] - nums[j];while(left < right){int sum = nums[left] + nums[right];if(sum < aim) left++;else if(sum > aim) right--;else{ret.push_back({nums[i], nums[j], nums[left++], nums[right--]});// 去重?while(left < right && nums[left] == nums[left - 1]) left++;while(left < right && nums[right] == nums[right + 1]) right--;}}// 去重?j++;while(j < n && nums[j] == nums[j - 1]) j++;}// 去重三i++;while(i < n && nums[i] == nums[i - 1]) i++;}return ret;}
};

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

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

相關文章

XRDMatch代碼復現與分析報告

XRDMatch代碼復現與分析報告 1. 項目概述 XRDMatch是一個用于X射線衍射(XRD)數據匹配和分析的開源工具,由zhengwan-chem開發并托管在GitHub上。本項目旨在復現XRDMatch的核心功能,并對其實現進行詳細分析。 X射線衍射是材料科學中用于確定晶體結構的重要技術,通過分析衍射…

SpringAI×Ollama:Java生態無縫集成本地大模型實踐指南

摘要 隨著大語言模型(LLM)的普及,數據隱私和技術棧統一性成為企業級AI應用的核心挑戰。本文系統闡述如何通過SpringAI框架與Ollama本地化模型引擎的結合,構建安全高效的生成式AI應用。通過實戰案例解析配置優化、流式響應、工具調用等關鍵技術,為Java開發者提供零Python依…

從采購申請到報廢核銷:如何用數字化縫合企業物資管理的“斷點”?

在企業的日常運營中&#xff0c;物資管理是一項至關重要的工作。從采購申請到物資的入庫、使用&#xff0c;再到最終的報廢核銷&#xff0c;這一系列流程就像一條長長的鏈條&#xff0c;環環相扣。然而&#xff0c;在傳統管理模式下&#xff0c;這條鏈條上卻存在著諸多“斷點”…

AVL平衡二叉樹

01. 初始AVL樹 AVL樹是最早發明的自平衡二叉搜索樹。在AVL樹中&#xff0c;任何節點的兩個子樹的高度差&#xff08;平衡因子&#xff09;最多為1&#xff0c;這使得AVL樹能夠保持較好的平衡性&#xff0c;從而保證查找、插入和刪除操作的時間復雜度都是O(log n)。包含n個節點…

教育行業可以采用Html5全鏈路對視頻進行加密?有什么優勢?

文章目錄前言一、什么是Html5加密&#xff1f;二、使用Html5對視頻加密的好處三、如何采用Html5全鏈路對視頻進行加密&#xff1f;四、教育行業采用Html5全鏈路視頻加密有什么優勢&#xff1f;總結前言 面對優質課程盜錄傳播的行業痛點&#xff0c;教育機構如何守護核心知識產…

Vue3 tailwindcss

1、安裝tailwindcsspnpm i -D tailwindcss postcss autoprefixer # yarn add -D tailwindcss postcss autoprefixer # npm i -D tailwindcss postcss autoprefixer2、 創建TailwindCSS配置文件npx tailwindcss init -ptailwind.config.js/** type {import(tailwindcss).Config}…

提示工程:解鎖大模型潛力的核心密碼

以下是對Lilian Weng的提示工程權威指南&#xff08;原文鏈接&#xff09;的深度解析與博客化重構&#xff0c;融入最新行業實踐&#xff1a; 提示工程&#xff1a;解鎖大模型潛力的核心密碼 ——從基礎技巧到工業級解決方案全解析 一、重新定義人機交互范式 傳統編程 vs 提示…

Python3郵件發送全指南:文本、HTML與附件

在 Python3 中&#xff0c;使用內置的 smtplib 庫和 email 模塊發送郵件是一個常見的需求。以下是更詳細的實現指南&#xff0c;包含各種場景的解決方案和技術細節&#xff1a;一、發送純文本郵件的完整實現準備工作&#xff1a;確保已開通 SMTP 服務&#xff08;各郵箱開啟方式…

CSS和CSS3區別對比

CSS&#xff08;層疊樣式表&#xff09;與CSS3&#xff08;CSS的第三個版本&#xff09;的區別主要體現在功能擴展、語法特性以及應用場景等方面。以下是兩者的核心對比&#xff1a; 一、核心概念與版本關系CSS&#xff1a;是基礎樣式表語言&#xff0c;用于分離網頁內容與樣式…

JVM--監控和故障處理工具

一、命令行工具 1. jps (Java Process Status) 作用&#xff1a;列出當前系統中所有的 Java 進程 常用命令&#xff1a; jps -l # 顯示進程ID和主類全名 jps -v # 顯示JVM啟動參數 輸出示例&#xff1a; 1234 com.example.MainApp 5678 org.apache.catalina.startup.Bootstra…

推薦 7 個本周 yyds 的 GitHub 項目。

01.開源的 CRM 軟件這是一個開源的客戶關系管理&#xff08;CRM&#xff09;系統&#xff0c;現在又 32.5K 的 Star。為企業和團隊提供比肩 Salesforce 等商業產品的功能&#xff0c;同時強調用戶自主權、數據自由與高度可定制性。開源地址&#xff1a;https://github.com/twen…

linux網絡編程之單reactor模型(一)

Reactor 是一種事件驅動的設計模式&#xff08;Event-Driven Pattern&#xff09;&#xff0c;主要用于處理高并發 I/O&#xff0c;特別適合網絡服務器場景。它通過一個多路復用機制監聽多個事件源&#xff08;如 socket 文件描述符&#xff09;&#xff0c;并在事件就緒時將事…

瀏覽器重繪與重排

深入解析瀏覽器渲染&#xff1a;重排(Reflow)與重繪(Repaint)的性能陷阱與優化策略作為一名前端開發者&#xff0c;你是否遇到過界面突然卡頓、滾動時頁面抖動或輸入框響應遲鈍&#xff1f;這些常見性能問題背后&#xff0c;往往是重排與重繪在作祟。本文將深入剖析瀏覽器渲染機…

day049-初識Ansible與常用模塊

文章目錄0. 老男孩思想-人脈的本質1. Ansible1.1 密鑰認證1.2 安裝ansible1.3 添加ansible配置文件1.4 配置主機清單文件&#xff08;Inventory&#xff09;1.5 測試1.6 ansible的模塊思想1.7 command模塊1.8 需求&#xff1a;每臺服務器的密碼都不同&#xff0c;怎么批量執行業…

力扣網編程134題:加油站(雙指針)

一. 簡介 前面兩篇文章使用暴力解法&#xff0c;或者貪心算法解決了力扣網的加油站問題&#xff0c;文章如下&#xff1a; 力扣網編程150題&#xff1a;加油站&#xff08;暴力解法&#xff09;-CSDN博客 力扣網編程150題&#xff1a;加油站&#xff08;貪心解法&#xff09…

XPath 語法【Web 自動化-定位方法】

&#x1f9ed; XPath 語法簡介&#xff08;Web 自動化核心定位手段&#xff09;一、XPath 是什么&#xff1f;XPath&#xff08;XML Path Language&#xff09;是用于在 XML/HTML 文檔中定位節點的語言&#xff0c;由 W3C 標準定義。瀏覽器支持的是 XPath 1.0。應用場景廣泛&am…

記一次 Linux 安裝 docker-compose

一.下載 1.手動下載 下載地址&#xff1a;https://github.com/docker/compose/releases 下載后&#xff0c;放在/usr/local/bin/目錄下&#xff0c;命名為&#xff1a;docker-compose 2.命令下載 sudo curl -L "https://github.com/docker/compose/releases/download/…

Go語言WebSocket編程:從零打造實時通信利器

1. WebSocket的魅力&#xff1a;為什么它這么火&#xff1f;WebSocket&#xff0c;簡單來說&#xff0c;就是一種在單條TCP連接上實現全雙工通信的神器。相比HTTP的請求-響應模式&#xff0c;它像是一條隨時暢通的電話線&#xff0c;客戶端和服務器可以隨時“喊話”&#xff0c…

速學 RocketMQ

目錄 本地啟動&測試&可視化 核心概念 集群 主從 集群 Dledger 集群 總結 客戶端消息確認機制 廣播模式 消息過濾機制 順序消息機制 延遲消息與批量消息 事務消息機制 ACL權限控制體系 RocketMQ客戶端注意事項 消息的 ID、Key、Tag 最佳實踐 消費者端…

【個人思考】不點菜的美學:Omakase 的信任、四季與食藝

本文原創作者:姚瑞南 AI-agent 大模型運營專家/音樂人/野生穿搭model,先后任職于美團、獵聘等中大廠AI訓練專家和智能運營專家崗;多年人工智能行業智能產品運營及大模型落地經驗,擁有AI外呼方向國家專利與PMP項目管理證書。(轉載需經授權) 目錄 ?? 什么是 Omakase?…