面試專題訓練之「雙指針」

1、須要思考的問題包括如下幾點:node

雙指針是什麼,何時須要用到雙指針數組

通用的模板是什麼ide

實現過程當中須要注意的細節有哪些函數

常見的雙指針題型有哪些spa

 

 

2、模板整理指針

 

 

3、專題訓練code

1.Leetcode283blog

 1 class Solution {  2 public:  3     void moveZeroes(vector<int>& nums) {  4         int n = nums.size();  5         int j = 0;  6         for (int i = 0; i < n; i++) {  7             if (nums[i] != 0) nums[j++] = nums[i];  8  }  9         while (j < n) { 10             nums[j++] = 0; 11  } 12  } 13 };
leetcode283

題意:給定一個數組,把 0 移動到末尾的位置,剩下非 0 的數的相對位置保持不變。排序

題解:至關於有兩個指針,都是從頭開始。一個指向爲 0 的值,一個指向非 0 的值。而後進行交換。three

 

2.Leetcode1248

class Solution { public: int numberOfSubarrays(vector<int>& nums, int k) { vector<int> ind; int n = nums.size(), ans = 0; ind.push_back(-1); for (int i = 0; i < n; i++) { if (nums[i] % 2 == 1) ind.push_back(i); } ind.push_back(n); int m = ind.size(); for (int i = 1; i+k-1 < m-1; i++) { int l = ind[i]; int r = ind[i+k-1]; int leftGap = l - ind[i-1]; int rightGap = ind[i+k] - r; ans += leftGap * rightGap; } return ans; } };
leetcode1248(解法1)
 1 class Solution {  2 public:  3     int numberOfSubarrays(vector<int>& nums, int k) {  4         return atMost(nums, k) - atMost(nums, k-1);  5  }  6     
 7     int atMost(vector<int>& nums, int k) {  8         int ans = 0, l = 0, n = nums.size();  9         for (int r = 0; r < n; r++) { 10             k -= (nums[r] & 1); 11             while (k < 0) { 12                 k += (nums[l++] & 1); 13  } 14             ans += (r - l + 1); 15  } 16         return ans; 17  } 18 };
leetcode1248(解法2)

題意:給定一個長度爲 n 的數組,求有多少個子數組知足其中包含 k 個奇數。

題解:

解法1:將全部奇數的下標保存起來,目的在於可以快速找到剛好包含 k 個奇數的子數組(/窗口),而後將該窗口向左右延申,可是不能破壞以前所知足的條件,在延申的過程當中的窗口都是答案。

解法2:添加函數 atMost 表示對於給定的數組,最多包含 k 個奇數的子數組有多少。這樣原問題的答案就變成了 atMost(k) - atMost(k-1)。在統計子數組個數時,設置兩個指針,右指針一直往右延申,每次延申一格,而後看當前的子數組 [l, r] 是否知足條件,若是不知足條件,則右移左指針直至符合條件,而後更新答案。

 

3.Leetcode350

 1 class Solution {  2 public:  3     vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {  4         unordered_map<int, int> mp;  5         for (int num : nums1) mp[num]++;  6         vector<int> ans;  7         int n = nums2.size();  8         for (int i = 0; i < n; i++) {  9             int num = nums2[i]; 10             if (mp[num] > 0) { 11  ans.push_back(num); 12                 mp[num]--; 13  } 14  } 15         return ans; 16  } 17 };
leetcode350

題意:給定兩個數組,求兩個數組的交集

題解:

方法1:用 unordered_map 存一個數組的數據,而後遍歷另一個數組去判斷 map 中是否存在那個數。

方法2:先對兩個數組進行排序,而後對於每一個數組設置指針指向頭部,比較並後移。

 

4.Leetcode16

 1 class Solution {  2 public:  3     int threeSumClosest(vector<int>& nums, int target) {  4  sort(nums.begin(), nums.end());  5         int n = nums.size();  6         int ans = nums[0] + nums[1] + nums[2];  7         for (int i = 0; i < n-2; i++) {  8             int j = i+1, k = n-1;  9             while (j < k) { 10                 int sum = nums[i] + nums[j] + nums[k]; 11                 if (abs(target-sum) < abs(target-ans)) ans = sum; 12                 if (sum < target) j++; 13                 else if (sum == target) return sum; 14                 else k--; 15  } 16  } 17         return ans; 18  } 19 };
leetcode16

題意:給定一個數組 nums,從中取出三個數,使得取出的三個數的和最接近給定的 target 值,問該值是多少。

題解:「三指針」,用 for i = [0 ~ n-2] 先肯定第一個指針的位置,而後剩下兩個指針,分別設定爲 l = i+1, r = n-1。在根據其nums[i]+nums[l]+nums[r] 的結果更新答案。

 

5.Leetcode75

 1 class Solution {  2 public:  3     void sortColors(vector<int>& nums) {  4         int n = nums.size();  5         int one, two, three;  6         one = two = three = 0;  7         for (int i = 0; i < n; i++) {  8             if (nums[i] == 0) {  9                 nums[three++] = 2; 10                 nums[two++] = 1; 11                 nums[one++] = 0; 12             } else if (nums[i] == 1) { 13                 nums[three++] = 2; 14                 nums[two++] = 1; 15             } else { 16                 nums[three++] = 2; 17  } 18  } 19  } 20 };
leetcode75(解法1)
 1 class Solution {  2 public:  3     void sortColors(vector<int>& nums) {  4         int n = nums.size();  5         int i, j, k;  6         i = j = 0, k = n - 1;  7         while (j <= k) {  8             if (nums[j] == 0) swap(nums[i++], nums[j++]);  9             else if (nums[j] == 1) j++; 10             else swap(nums[j], nums[k--]); 11  } 12  } 13 };
leetcode75(解法2)

題意:給定一個只包含數字 1 2 3 的數組 nums,只遍歷一遍實現原地更新。

題解:

1.記值爲 0 的數字個數爲 a,值爲 1 的數字個數爲 b,值爲 2 的數字個數爲 c. 這樣能夠保證 [0, a) 的位置的值全爲 0,[a, a+b) 的位置的值全爲 1,[a+b, a+b+c) 的位置的值全爲 2。咱們用變量 one 表明值 <= 0 的數的個數(/位置),用變量 two 表明值 <= 1 的數的個數,用變量 three 表明值 <= 2 的數的個數。這樣每次訪問到 nums[i] == 0 時,那麼咱們須要按照 three -> two -> one 的順序依次更新各個值。 每次訪問到 nums[i] == 1 時,那麼咱們須要按照 three -> two 的順序依次更新各個值。 每次訪問到 nums[i] == 2 時,那麼咱們須要按照 three  的順序依次更新各個值。 這樣能夠保證先前暫時被寫到前面位置的大值被覆蓋。

2.「三指針」,用 i 表明值爲 0 的數的位置,j 表明值爲 1 的數的位置,k 表明值爲 2 的數的位置。初始時 i = j = 0, k = n-1. 在整個過程當中移動 j 的值,遇到 0,就交換 nums[i++] 和 nums[j++] 確保值 0 必定能夠放到前面。遇到 1,則 j++。遇到 2,就交換 nums[j] 和 nums[k--],確保值 2 必定放在最後。即 0 是從開頭日後增加,2 是從最後往前增加,而 1 是根據 0 和 2 的位置調整變更的。

 

7.Leetcode19

 1 /**  2  * Definition for singly-linked list.  3  * struct ListNode {  4  * int val;  5  * ListNode *next;  6  * ListNode(int x) : val(x), next(NULL) {}  7  * };  8  */
 9 class Solution { 10 public: 11     ListNode* removeNthFromEnd(ListNode* head, int n) { 12         if (n == 0) return head->next; 13         ListNode* fast = head; 14         ListNode* slow = head; 15         for (int i = 0; i < n; i++) fast = fast->next; 16         if (fast == NULL) return slow->next; 17         while (fast->next != NULL) { 18             fast = fast->next; 19             slow = slow->next; 20  } 21         slow->next = slow->next->next; 22         return head; 23  } 24 };
leetcode19

題意:給定一個鏈表,去掉倒數第 k 個數。

題解:這裏只給出了 one pass 的解法。由於要將倒數第 k 個數刪掉,這裏咱們採用「快慢指針」 的作法,讓快指針先走 k 個數。這樣就能保證當快指針走到末尾時,滿指針所在的位置就是要去掉的位置。

相關文章
相關標籤/搜索