算法学习之双指针

2023-11-01

  今天我们来学习两种算法双指针(滑动窗口)与位运算。

  在数组问题中,我们可以使用两个指针分别指向数组的不同位置,根据问题的要求移动指针来进行遍历或搜索。常见的双指针技巧包括:

  1. 快慢指针:这种情况下,一个指针移动的速度较快(每次移动多个元素),而另一个指针移动的速度较慢(每次只移动一个元素)。这种技巧常用于解决链表中的问题,如判断链表是否有环,找到链表的中间节点等。

  2. 左右指针:这种情况下,一个指针从数组的左侧开始移动,而另一个指针从数组的右侧开始移动,直到两个指针相遇。这种技巧常用于解决数组中的问题,如查找数组中的某个区间、判断数组是否为回文等。

  3. 对撞指针:这种情况下,两个指针分别从数组的两端开始移动,并逐步向中间靠拢。这种技巧常用于解决有序数组中的问题,如在有序数组中查找两个数之和等。

  以洛谷P1147为例子,这题就是典型的双指针问题,并且还附带了上一篇的前缀和问题。

  题目给的数据是200万,如果我们使用朴素写法,两个for循环遍历的话,肯定超时。但是如果我们使用双指针算法,那就只需要O(n)级别的时间复杂度即可。

  设定指针 i = 0, j = 0 ,因为数组是有序的,所以我们可以通过判断 sum[j] - sum[i] 和M的大小,来分别改变指针i,j的位置,并且如果a[j] - a[i] = M,则找到了答案,输出即可。

  我的AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define MAX 2000005
 4 typedef long long ll;
 5 int M;
 6 ll sum[MAX];
 7 ll a[MAX];
 8 int main(){
 9     cin>>M;
10     sum[0]=0;
11     for(int i = 1;i<=M;i++){
12         a[i] = i;
13         sum[i] = sum[i-1] + a[i];
14     }
15     for(int l=0,r=0;r<=M;){
16         if(sum[r]-sum[l]<M){
17             r++;
18         }
19         else if(sum[r]-sum[l]>M){
20             l++;
21             r--;
22         }
23         else if(sum[r]-sum[l]==M){
24             if(r==M) break;
25             cout<<l+1<<' '<<r<<endl;
26             l++;
27         }
28     }
29     return 0;
30 }

  可以去写一下P1102 A-B 数对 是一道非常好的双指针的题。

posted @ 2023-11-01 22:11  Linglo  阅读(54)  评论(0)    收藏  举报