1、基本概念
雙指標主要分為以下三種:
普通的指標:兩個指標往一個方向移動
對撞指標:一般是在有序的情況下兩個指標進行面對面的移動,適合解決約束條件的一組元素問題以及字串反轉問題
快慢指標:定義兩個指標,一個快指標一個慢指標,用於判斷是否為環或者長度的問題很方便
透過一個快指標和慢指標在一個for迴圈下完成兩個for迴圈的工作,把輸出的陣列直接寫在輸入陣列上。
右指標 fast 指向當前將要處理的元素,左指標 slow 指向下一個將要賦值的位置。
如果 fast 指標指向的元素不等於 val,它一定是輸出陣列的一個元素,我們就將 fast 指標指向的元素複製到 slow 指標位置,然後將兩個指標同時右移;
如果右指標指向的元素等於 val,它不能在輸出陣列裡,此時 slow 指標不動,fast 指標右移一位。
整個過程保持不變的性質是:區間 [0,slow) 中的元素都不等於val。當左右指標遍歷完輸入陣列以後,slow 的值就是輸出陣列的長度。
2、程式碼實現
1 class Solution {
2 public:
3 int removeElement(vector<int>& nums, int val) {
4 // 雙指標
5 int slow = 0;
6 int n = nums.size();
7 for (int fast = 0; fast < n; fast++){
8 if (nums[fast] != val){
9 nums[slow] = nums[fast];
10 slow++;
11 }
12 }
13 return slow;
14 }
15 };
3、降低時間複雜度
假設我們有一個二維陣列arr,大小為n x m,我們要對其進行雙層迴圈遍歷,原始碼如下:
1 for (int i = 0; i < n; i++) {
2 for (int j = 0; j < m; j++) {
3 // 執行操作
4 }
5 }
我們使用雙指標最佳化這個迴圈。首先,我們定義兩個指標p1和p2,初始時分別指向陣列的第一個元素。然後,我們使用一個迴圈來遍歷陣列,每次迭代更新指標的位置,並執行操作
1 int p1 = 0; // 第一個指標初始位置
2 int p2 = 0; // 第二個指標初始位置
3
4 while (p1 < n && p2 < m) {
5 // 執行操作
6
7 // 更新指標的位置
8 p2++;
9 if (p2 == m) {
10 p2 = 0;
11 p1++;
12 }
13 }
4、例題
給定一個有序的遞增陣列,陣列arr={1,3,4,9,11,12,14},找到兩個數之和為12,找到一組即可停止
思路:這題最容易想到的就是暴力演算法,即直接兩層迴圈巢狀逐個查詢,但時間複雜度為:O(n^2)
暴力演算法:
1 for(int i=0;i<n;i++){
2 for(int j=0;j<n;j++){
3 if(arr[i]+arr[j]==k)
4 cout<<arr[i]<<arr[j]>>endl;
5 }
6 }
雙指標:這題使用雙指標大大降低了時間複雜度
1 int i = 0; // 從頭開始的索引
2 int j = arr.size() - 1; // 從尾開始的索引
3
4 while (i < j)
5 {
6 if (arr[i] + arr[j] < k)
7 {
8 i++; // 如果arr[i]和arr[j]的和小於k,則增加i的值
9 }
10 else if (arr[i] + arr[j] > k)
11 {
12 j--; // 如果arr[i]和arr[j]的和大於k,則減小j的值
13 }
14 else
15 {
16 cout << arr[i] << arr[j] << endl; // 如果arr[i]和arr[j]的和等於k,則輸出這兩個數並結束迴圈
17 break;
18 }
19 }
20
21 return 0;