16. 最接近的三数之和 相对于暴力解法,双指针能够通过首尾指针和合理移动,减少不合理情况的遍历,即a+b+c < target,则c向左移动,a+b+c > target,b向右移动
进一步可以总结出:若想要使两数之和逼近某一个目标值 ,可使用双指针对已排序数组进行查找
对已排序数组的遍历时跳过重复值 的通用优化:
1 2 3 int p0 = p + 1 ;while (nums[p0] == nums[p] && p0 < q) p0++;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 int threeSumClosest (vector <int >& nums, int target) { int ans = 1e7 ; int n = nums.size(); sort(nums.begin(), nums.end()); int sum; auto update = [&](int cur) { if (abs (cur - target) < abs (ans - target)) { ans = cur; } }; for (int i = 0 ; i < n - 2 ; i++) { if (i > 0 && nums[i] == nums[i-1 ]) continue ; int p = i + 1 ; int q = n - 1 ; while (p < q) { sum = nums[i] + nums[p] + nums[q]; if (sum == target) { return target; } update(sum); if (sum < target) { int p0 = p + 1 ; while (nums[p0] == nums[p] && p0 < q) p0++; p = p0; } if (sum > target) { int q0 = q - 1 ; while (q0 > p && nums[q0] == nums[q]) { q0--; } q = q0; } } } return ans; }
19. 删除链表的倒数第N个节点 怎样一次遍历找到倒数第N个节点? 双指针,前面的指针在后面的指针前N+1的位置,同步前进,然后当前面的指针指到nullptr时,后面的指针处于倒数N+1位置,这时令:
1 p->next = p->next->next;
怎样保证最后返回正确的头节点?(原链表的头节点可能被删除) 开始时在head前new一个节点hair:
1 ListNode* hair = new ListNode(0 , head);
最后返回hair->next
18. 四数之和 先将数组用sort()进行排序
双重循环遍历前两个数,后两个数分配双指针一前一后
外面双重循环:
1 2 3 4 5 6 7 for (int i = 0 ; i < n-3 ; i++) { for (int j = i+1 ; j < n-2 ; j++) { ...... } }
双指针起始位置:
1 2 int p = j + 1 ;int q = n - 1 ;
剪枝操作:
在外层的两重循环中分别做如下几种情况的剪枝:
当前值nums[i]与上一个值nums[i-1]相同时,continue
当前值nums[i]加上后面连续三个数nums[i+1], nums[i+2], nums[i+3]的和大于target,则之后不论如何取值都一定大于target,直接跳出循环break
当前值nums[i]加上倒数三个最大的值nums[n-1], nums[n-2], nums[n-3]的和小于target,说明以nums[i]起始的任意四个数的和均小于target,跳出本次循环continue
对于第二层循环做类似的三种情况的剪枝处理
415. 字符串相加 实现两个字符串的数值相加,不能用类型转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 string addStrings (string num1, string num2) { int i = num1.length() - 1 ; int j = num2.length() - 1 ; string res; int multi = 1 ; int add = 0 ; while (i >= 0 || j >= 0 || add > 0 ) { int x = 0 ; int y = 0 ; if (i >= 0 ) { x = num1[i] - '0' ; } if (j >= 0 ) { y = num2[j] - '0' ; } int result = x + y + add; res.push_back('0' + result % 10 ); add = result / 10 ; i--; j--; } reverse(res.begin(), res.end()); return res; }
75. 颜色分类 数组中只有0,1,2三种值,对其排序的方式:
双指针p0和p2,p0用于交换0,p2用于交换2
p0 = 0,p2 = n - 1
一次遍历,当前值如果为0,交换当前位置和p0位置的值,当前值如果为2,和p2交换
1 2 3 4 5 6 7 8 9 10 11 while (i <= p2 && nums[i] == 2 ) { swap(nums[i], nums[p2]); --p2; }if (nums[i] == 0 ) { swap(nums[i], nums[p0]); ++p0; }