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 };
题意:给定一个数组,把 0 移动到末尾的位置,剩下非 0 的数的相对位置保持不变。排序
题解:至关于有两个指针,都是从头开始。一个指向为 0 的值,一个指向非 0 的值。而后进行交换。three


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; } };


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 };
题意:给定一个长度为 n 的数组,求有多少个子数组知足其中包含 k 个奇数。
题解:
解法1:将全部奇数的下标保存起来,目的在于可以快速找到刚好包含 k 个奇数的子数组(/窗口),而后将该窗口向左右延申,可是不能破坏以前所知足的条件,在延申的过程当中的窗口都是答案。
解法2:添加函数 atMost 表示对于给定的数组,最多包含 k 个奇数的子数组有多少。这样原问题的答案就变成了 atMost(k) - atMost(k-1)。在统计子数组个数时,设置两个指针,右指针一直往右延申,每次延申一格,而后看当前的子数组 [l, r] 是否知足条件,若是不知足条件,则右移左指针直至符合条件,而后更新答案。


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 };
题意:给定两个数组,求两个数组的交集
题解:
方法1:用 unordered_map 存一个数组的数据,而后遍历另一个数组去判断 map 中是否存在那个数。
方法2:先对两个数组进行排序,而后对于每一个数组设置指针指向头部,比较并后移。


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 };
题意:给定一个数组 nums,从中取出三个数,使得取出的三个数的和最接近给定的 target 值,问该值是多少。
题解:“三指针”,用 for i = [0 ~ n-2] 先肯定第一个指针的位置,而后剩下两个指针,分别设定为 l = i+1, r = n-1。在根据其nums[i]+nums[l]+nums[r] 的结果更新答案。


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 };


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 };
题意:给定一个只包含数字 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 的位置调整变更的。


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 };
题意:给定一个链表,去掉倒数第 k 个数。
题解:这里只给出了 one pass 的解法。由于要将倒数第 k 个数删掉,这里咱们采用“快慢指针” 的作法,让快指针先走 k 个数。这样就能保证当快指针走到末尾时,满指针所在的位置就是要去掉的位置。