雙指針技巧在C++中的應用:從基礎到進階

目錄

1.簡介

2.同向雙指針

2.1.數組去重

2.2.最大子數組和

2.3.鏈表反轉

2.4.字符串匹配(簡單版)

3.對向雙指針

3.1.兩數之和(有序數組)

3.2.盛最多水的容器

4.快慢指針

4.1.判斷鏈表是否有環

4.2.尋找鏈表的中間節點

4.3.合并兩個有序鏈表

5.總結


1.簡介

????????雙指針技巧是一種常見的算法技巧,廣泛應用于排序、查找、求和等問題中,尤其在處理數組、鏈表等數據結構時,表現出顯著的優勢。通過合理地使用兩個指針來解決問題,可以減少時間復雜度,提升算法效率。

????????雙指針技巧在 C++ 中應用廣泛,能高效解決諸多算法問題,主要分為同向雙指針、對向雙指針和快慢雙指針這幾類。

????????以下結合具體應用案例來介紹。

2.同向雙指針

2.1.數組去重

????????給定一個有序數組,要求去除重復元素并返回新數組的長度。以[1, 1, 2, 2, 3, 4]為例,借助同向雙指針,慢指針slow用于記錄不重復元素的存儲位置,快指針fast遍歷數組。當fast指向的元素與slow指向的元素不同時,將fast指向的元素賦值給slow + 1的位置,然后slow后移。

? ? ? ? 代碼如下:

int removeDuplicates(vector<int>& nums) {if (nums.empty()) return 0;int slow = 0;for (int fast = 1; fast < nums.size(); ++fast) {if (nums[fast] != nums[slow]) {nums[++slow] = nums[fast];}}return slow + 1;
}

2.2.最大子數組和

給定一個整數數組,找出具有最大和的連續子數組(子數組至少包含一個元素)。

思路

  1. 使用一個指針來表示當前的窗口區間。

  2. 每次擴展窗口,計算窗口內的元素和,并更新最大和。

  3. 一旦當前窗口的和小于0,可以通過左指針縮小窗口,減少不必要的計算。

#include <iostream>
#include <vector>
usingnamespacestd;int maxSubArray(const vector<int>& nums) {int max_sum = nums[0], current_sum = nums[0];for (int i = 1; i < nums.size(); i++) {current_sum = max(nums[i], current_sum + nums[i]);max_sum = max(max_sum, current_sum);}return max_sum;
}int main() {vector<int> nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};cout << "Maximum Subarray Sum: " << maxSubArray(nums) << endl;return 0;
}

2.3.鏈表反轉

反轉鏈表的經典問題,可以通過雙指針技巧進行高效處理。

思路

  1. 使用兩個指針,一個指向當前節點,另一個指向前一個節點。

  2. 每次將當前節點的指針指向前一個節點,逐步反轉鏈表。

#include <iostream>
usingnamespacestd;struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};ListNode* reverseList(ListNode* head) {ListNode* prev = nullptr;ListNode* current = head;while (current != nullptr) {ListNode* nextNode = current->next;current->next = prev;prev = current;current = nextNode;}return prev;
}void printList(ListNode* head) {ListNode* temp = head;while (temp != nullptr) {cout << temp->val << " ";temp = temp->next;}cout << endl;
}int main() {ListNode* head = new ListNode(1);head->next = new ListNode(2);head->next->next = new ListNode(3);head->next->next->next = new ListNode(4);cout << "Original List: ";printList(head);ListNode* reversed = reverseList(head);cout << "Reversed List: ";printList(reversed);return 0;
}

2.4.字符串匹配(簡單版)

????????在一個長字符串中查找短字符串首次出現的位置(簡單的暴力匹配改進)。比如在字符串"ABABDABACDABABCABAB"中找"ABABC"。長字符串指針i和短字符串指針j同向移動,當j指向的字符與i指向的字符匹配時,ij都后移;若不匹配,i回退到上次匹配起始位置的下一個位置,j歸零重新匹配。

? ? ? ? 具體代碼如下:

int strStr(string haystack, string needle) {int m = haystack.size(), n = needle.size();for (int i = 0; i <= m - n; ++i) {int j = 0;for (; j < n; ++j) {if (haystack[i + j] != needle[j]) {break;}}if (j == n) {return i;}}return -1;
}

3.對向雙指針

3.1.兩數之和(有序數組)

假設有一個排序好的數組,我們需要在該數組中找到兩個數,使得它們的和等于目標值。

思路

  1. 定義兩個指針,分別指向數組的開頭和結尾。

  2. 根據當前兩指針指向的數值之和與目標值的關系,決定移動哪個指針。

  3. 如果兩數之和大于目標值,則移動右指針,減小和;如果小于目標值,則移動左指針,增大和。

? ? ? ? 具體代碼如下:

#include <iostream>
#include <vector>
usingnamespacestd;bool twoSum(const vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;while (left < right) {int sum = nums[left] + nums[right];if (sum == target) {return true;} elseif (sum < target) {left++;} else {right--;}}return false;
}int main() {vector<int> nums = {1, 2, 3, 4, 6};int target = 10;cout << (twoSum(nums, target) ? "Found" : "Not found") << endl;return 0;
}

3.2.盛最多水的容器

????????給定一個數組,數組中的每個元素表示一個垂直的線段高度,線段之間的距離是相鄰元素的索引差,要求找出兩條線段,使得它們與 x 軸構成的容器能容納最多的水。以[1, 8, 6, 2, 5, 4, 8, 3, 7]為例,使用對向雙指針,指針leftright分別指向數組兩端。計算當前容器的面積area = min(height[left], height[right]) * (right - left),更新最大面積。然后比較height[left]height[right],較小值對應的指針向內移動,重復計算面積和移動指針的操作。

? ? ? ? 具體代碼如下:

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

4.快慢指針

????????快慢指針的基本思路是:用兩個指針(通常稱為快指針和慢指針)遍歷數據結構。慢指針每次移動一步,而快指針每次移動兩步。由于快指針移動的速度較快,它可以在一些特定場景下幫助我們高效地解決問題。

4.1.判斷鏈表是否有環

????????環形鏈表是一個常見的數據結構問題,要求檢測鏈表中是否存在環。使用快慢指針的算法非常高效。基本思路是:讓快指針每次走兩步,慢指針每次走一步。如果鏈表中存在環,快慢指針最終會相遇;如果鏈表沒有環,快指針會先到達鏈表的尾部。

? ? ? ? 具體實現代碼如下:

#include <iostream>struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};bool hasCycle(ListNode* head) {if (!head || !head->next) returnfalse;ListNode* slow = head;ListNode* fast = head;while (fast && fast->next) {slow = slow->next;           // 慢指針每次走一步fast = fast->next->next;     // 快指針每次走兩步if (slow == fast) return true; // 快慢指針相遇,說明有環}return false; // 快指針到達鏈表尾部,沒有環
}int main() {ListNode* head = new ListNode(1);head->next = new ListNode(2);head->next->next = new ListNode(3);head->next->next->next = new ListNode(4);head->next->next->next->next = head->next; // 創建環if (hasCycle(head)) {std::cout << "The linked list has a cycle." << std::endl;} else {std::cout << "The linked list does not have a cycle." << std::endl;}return0;
}

4.2.尋找鏈表的中間節點

????????另一個常見的應用是查找鏈表的中間節點。使用快慢指針時,慢指針每次走一步,快指針每次走兩步。當快指針走到鏈表末尾時,慢指針恰好到達中間節點。

????????具體實現代碼如下:

#include <iostream>struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};ListNode* findMiddle(ListNode* head) {if (!head) returnnullptr;ListNode* slow = head;ListNode* fast = head;while (fast && fast->next) {slow = slow->next;fast = fast->next->next;}return slow; // 慢指針指向鏈表的中間節點
}int main() {ListNode* head = new ListNode(1);head->next = new ListNode(2);head->next->next = new ListNode(3);head->next->next->next = new ListNode(4);head->next->next->next->next = new ListNode(5);ListNode* middle = findMiddle(head);if (middle) {std::cout << "The middle node value is: " << middle->val << std::endl;} else {std::cout << "The list is empty." << std::endl;}return0;
}

4.3.合并兩個有序鏈表

????????在合并兩個有序鏈表時,可以使用雙指針來實現。雖然這不是嚴格的快慢指針技巧,但它與快慢指針有一定的相似性。通過兩個指針分別遍歷兩個鏈表并比較元素,逐步合并鏈表。

????????具體實現代碼如下:

#include <iostream>struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {ListNode dummy(0);ListNode* current = &dummy;while (l1 && l2) {if (l1->val < l2->val) {current->next = l1;l1 = l1->next;} else {current->next = l2;l2 = l2->next;}current = current->next;}if (l1) current->next = l1;if (l2) current->next = l2;return dummy.next;
}int main() {ListNode* l1 = new ListNode(1);l1->next = new ListNode(3);l1->next->next = new ListNode(5);ListNode* l2 = new ListNode(2);l2->next = new ListNode(4);l2->next->next = new ListNode(6);ListNode* mergedList = mergeTwoLists(l1, l2);while (mergedList) {std::cout << mergedList->val << " ";mergedList = mergedList->next;}std::cout << std::endl;return0;
}

5.總結

????????在算法題中,雙指針具有很多應用,那么在實際項目中,你有使用過雙指針技巧嗎?主要是什么場景?歡迎評論區交流討論~

推薦閱讀

滑動窗口算法詳解:概念、應用與實例,-CSDN博客

C++合并兩個有序數組-CSDN博客?

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

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

相關文章

語言解碼雙生花:人類經驗與AI算法的鏡像之旅

大家好&#xff0c;我是吾鳴。 今天吾鳴要給大家分享一份由浙江大學出品的DeepSeek報告&#xff0c;報告從語言的奧秘&#xff0c;人類是如何通過語言來解碼世界&#xff0c;AI又是如何理解人類的語言&#xff0c;同時介紹了當下爆火的DeepSeek-V3和DeepSeek-R1兩種大模型的進化…

如何避免測試數據準備不充分或不可復用

避免測試數據準備不充分或不可復用的關鍵方法包括明確數據需求、統一數據管理工具、建立數據復用機制、定期維護更新測試數據以及加強團隊溝通與協作。 其中&#xff0c;統一數據管理工具對確保數據質量和復用性尤為重要。例如&#xff0c;許多團隊采用專門的測試數據管理工具以…

HTTP 核心知識點整理

1. HTTP 基礎 ?定義&#xff1a;HTTP&#xff08;HyperText Transfer Protocol&#xff09;是應用層協議&#xff0c;基于 ?請求-響應模型&#xff0c;用于客戶端&#xff08;瀏覽器&#xff09;與服務器之間的通信。?特點&#xff1a; ?無狀態&#xff1a;每次請求獨立&a…

湯臣倍健業績倒車:2024年利潤下滑超六成,三大核心品牌銷量失守

撰稿|行星 來源|貝多財經 湯臣倍健的2024年&#xff0c;“隱痛”不少。 3月22日&#xff0c;國內膳食營養補充劑供應商湯臣倍健股份有限公司&#xff08;SZ:300416&#xff0c;下稱“湯臣倍健”&#xff09;公布了2024年年度報告。財報顯示&#xff0c;湯臣倍健過去一年出現了…

C#中的Lambda表達式?

在C#中&#xff0c;?Lambda表達式?是一種比匿名方法更簡潔、更靈活的語法形式&#xff0c;用于定義匿名函數&#xff08;Anonymous Function&#xff09;。它通過>運算符實現&#xff0c;能夠大幅簡化委托和表達式樹的編寫&#xff0c;是現代C#編程中廣泛使用的核心特性之…

通信系統的性能指標

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、通信系統的性能指標概述二、數字通信系統的有效性指標三、數字通信系統的可靠性指標總結 前言 一、通信系統的性能指標概述 其中一個提高&#xff0c;另一個…

Linux:(模擬HTTP協議,GET和POST方法,Http的狀態碼)

目錄 一、認識HTTP協議 1.上網的本質 2.應用層的運行邏輯 3.HTTP的概念 二、url 1.認識網址 三、HTTP協議的宏觀理解 1.HTTP請求 2.HTTP響應 3.實際的HTTP請求 &#xff08;1&#xff09;測試代碼 &#xff08;2&#xff09;接收HTTP請求 &#xff08;3&#xff09…

動態規劃之完全背包

引言&#xff1a; 完全背包 隸屬于動態規劃中的背包問題。而 01背包 又是完全背包的基石&#xff0c;所以不懂01背包的&#xff0c;有必要了解一下。 什么是完全背包&#xff1f; 01背包問題&#xff1a;有一個背包承重為V&#xff0c;有N個物品&#xff0c;每個物品的價值(…

Codeforces Round 1003 (Div. 4)

ABCDE略 F 如果這個序列有兩個一樣的數挨著或者中間只隔一個其他的數&#xff0c;那么這個數就是多數。可以用反證法&#xff0c;構造一個多值序列無法不包含以上兩種結構。只需要在樹上找這兩種結構就可以了 #include <bits/stdc.h> #define int long long using nam…

金融數據分析(MATLAB)個人學習筆記(5):金融實證分析實例

一、國內外常用金融數據庫簡介 &#xff08;一&#xff09;國外數據庫 1. CRSP數據庫 CRSP&#xff08;Center for Research in Security Prices,證券價格研究中心&#xff09;是美國芝加哥大學商研所金融研究中心的產品。收集的美國股票和指數數據來源主要為紐約證券交易所…

硬件基礎(3):三極管(4):關于三極管的壓降

文章目錄 三極管的壓降使用與測量注意事項 三極管的壓降 三極管的“壓降”通常是指在一定工作狀態下&#xff0c;三極管不同電極之間產生的電壓差。對于常見的雙極性晶體管&#xff08;BJT&#xff09;而言&#xff0c;最常討論的壓降通常包括以下幾個部分&#xff1a; 基-發射…

[深度學習]圖像分類項目-食物分類

圖像分類項目-食物分類(監督學習和半監督學習) 文章目錄 圖像分類項目-食物分類(監督學習和半監督學習)項目介紹數據處理設定隨機種子讀取文件內容圖像增廣定義Dataset類 模型定義遷移學習 定義超參Adam和AdamW 訓練過程半監督學習定義Dataset類模型定義定義超參訓練過程 項目介…

5.go切片和map

切片的概念 數組和切片相比較切片的長度是不固定的&#xff0c;可以追加元素&#xff0c;在追加時可能會使切片的容量增大&#xff0c;所以可以將切片理解成 "動態數組"&#xff0c;但是&#xff0c;它不是數組&#xff0c;而是構建在數組基礎上的更高級的數據結構。…

在 Windows 上安裝 PowerShell 的多種方法與完整指南

原文&#xff1a;在 Windows 上安裝 PowerShell 的多種方法與完整指南 | w3cschool筆記 在 Windows 上安裝 PowerShell 有多種方式。每種安裝方法都適用于不同的場景和工作流。請選擇最適合您需求的方法。 WinGet&#xff1a;推薦在 Windows 客戶端上安裝 PowerShell 的方式MS…

云原生算力引擎:分布式推理的流體動力學

引言&#xff1a;算力黑洞的引力擾動 OpenAI推理集群日處理4.5億次請求&#xff0c;CUDA 12.3實現μs級張量切換。特斯拉Dojo超算芯片間延遲0.5ns&#xff0c;阿里巴巴PAI平臺節省58%訓練時長。HuggingFace模型庫下載量突破3億次&#xff0c;AWS Inferentia芯片能效比提升8倍。…

MySQL MVCC的快照讀和當前讀區別,Redis的RDB+AOF混合持久化流程。

MySQL MVCC 的快照讀和當前讀區別 快照讀 (Snapshot Read) 定義: 讀取數據的歷史版本&#xff08;快照&#xff09;&#xff0c;基于 MVCC&#xff08;多版本并發控制&#xff09;實現。特點: 不加鎖&#xff0c;非阻塞讀。返回事務開始時的快照數據&#xff0c;確保一致性。…

Cesium 自定義路徑導航材質

cesium 自定義路徑導航紋理圖片隨便更換&#xff0c;UI 提供設計圖片即可達到效果&#xff1b; 打開小馬的weix 關注下 搜索“技術鏈” 回復關鍵詞《《路徑》》獲取原始代碼&#xff1b; 拿到就能用輕松解決&#xff01;幫忙點個關注吧&#xff01;

3月25號

添加圖片的一些例子: // 創建一個二維數組,用來管理數據int[][] data new int[4][4]; // 記錄空白方塊的位置int x0;int y0; // 定義一個變量,記錄當前展示圖片的路徑String path"E:\\java\\jigsawgame\\路飛\\路飛"; // 加載圖片細節: // …

【機器學習】什么是支持向量機?

什么是支持向量機&#xff1f; 支持向量機&#xff08;SVM&#xff0c;Support Vector Machine&#xff09;是一種強大的機器學習算法&#xff0c;常用于分類問題&#xff0c;也可以用于回歸問題。它的核心思想是通過找到一個最佳的“超平面”來將不同類別的數據分開&#xff…

10分鐘打造專屬AI助手!ToDesk云電腦/順網云/海馬云操作DeepSeek哪家強?

文章目錄 一、引言云計算平臺概覽ToDesk云電腦&#xff1a;隨時隨地用上高性能電腦 二 .云電腦初體驗DeekSeek介紹版本參數與特點任務類型表現 1、ToDesk云電腦2、順網云電腦3、海馬云電腦 三、DeekSeek本地化實操和AIGC應用1. ToDesk云電腦2. 海馬云電腦3、順網云電腦 四、結語…