双指针其实不是真正的指针,而是有两个变量在序列上进行一些操作。
——Lqingyi(Lxandqi)
思想分类
- 普通双指针 也就是两个普通的
for
(也可以是其他的)循环嵌套。 - 左右指针 其实就是二分搜索,一个变量指向开头,一个变量指向末尾,根据条件向中间遍历,直到指针相遇或满足某种条件。(也就是逼近答案)
- 快慢指针 两个指针(变量)开始同时开头,但一个遍历的快,一个慢,直到条件满足或指针到末尾。
提示
双指针是二重循环。
一般来说,快慢指针的第二个指针(快指针)的变量是在 for
循环体之外定义的。因为 for
循环会初始化变量。快慢指针的变量是不可以初始化的,因为已经遍历过的就不用遍历了,再遍历一遍就变成普通双指针(暴力枚举)了。
怎么感觉只有例题才能讲清楚???
例题
给定一个长度为 $n$ 的整数序列 $a_1,a_2,…,a_n$ 以及一个长度为 $m$ 的整数序列 $b_1,b_2,…,b_m$。
请你判断 $a$ 序列是否为 $b$ 序列的子序列。
子序列指序列的一部分项按原有次序排列而得的序列,例如序列 $a_1,a_3,a_5$ 是序列 $a_1,a_2,a_3,a_4,a_5$ 的一个子序列。
输入时:
第一行包含两个整数 $n,m$。
第二行包含 $n$ 个整数,表示 $a_1,a_2,…,a_n$。
第三行包含 $m$ 个整数,表示 $b_1,b_2,…,b_m$。
输出时:
如果 $a$ 序列是 $b$ 序列的子序列,输出一行 Yes
。
否则,输出 No
。
数据保证:
$1 \le n \le m \le 10^5$
$−10^9 \le a_i,b_i \le 10^9$
解题:
数据那么大,暴枚肯定不行。那么就用今天学的双指针。
一个指针 $i$ 遍历数组 $a$ 的元素,指针 $j$ 遍历数组 $b$ 的元素。写一个 while(1)
死循环, $j$ 在 while
中每次 ++
,如果 $a_i = b_j$ ,则 break
,如果 $j > m$ 则输出 No
。 $j$ 变量(指针)的定义要写在循环之外。
代码:
#include <cstdio>
using namespace std;
int n, m ;
const int N = 1e5 + 5 ;
int a[N], b[N] ;
int main()
{
scanf("%d %d", &n, &m) ;
for(int i = 1; i <= n; i++) scanf("%d", &a[i]) ;
for(int i = 1; i <= m; i++) scanf("%d", &b[i]) ;
int j = 1 ;
for(int i = 1; i <= n; i++)
{
while(1)
{
if(j > m)
{
printf("No\n") ;
return 0 ;
}
if(a[i] == b[j])
{
j++ ;
break ;
}
j++ ;
}
}
printf("Yes\n") ;
return 0 ;
}