双指针法
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;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步