神机百炼1.16-单调双指针

单调双指针导图

食用指南:

对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目侧重题目分析,代码实现,以及必要的代码理解误区

题目描述:

  • 给定两个升序排序的有序数组 A 和 B,以及一个目标值 x。
    数组下标从 0 开始。
    请你求出满足 A[i]+B[j]=x 的数对 (i,j)。
    数据保证有唯一解。

    输入格式
    第一行包含三个整数 n,m,x,分别表示 A 的长度,B 的长度以及目标值 x。
    第二行包含 n 个整数,表示数组 A。
    第三行包含 m 个整数,表示数组 B。

    输出格式
    共一行,包含两个整数 i 和 j。

    数据范围
    数组长度不超过 105。
    同一数组内元素各不相同。
    1≤数组元素≤109
    输入样例:
    4 5 6
    1 2 4 7
    3 4 6 8 9
    输出样例:
    1 1

  • 题目来源:https://www.acwing.com/problem/content/802/

题目分析:

  • 双串双指针,没什么好硕的
    第一次见这个概念的同学看这里~:传送门
  • 暴力双指针:
    两层循环,一层枚举数组A,一层枚举数组B,当A[i]+B[j] == x时停下来输出i & j
    最坏时间复杂度:O(nm)
    n最大十万,m最大十万,nm又一个拼多多百亿补贴,必然超时
  • 单调双指针:
    当数组本身具有单调性时,拒绝盲目枚举
    让双指针的移动方向唯一确定后,可以达到O(m+n)的时间复杂度
    下面讲解单调双指针算法

算法原理:

要求:

  • 两个子串具有单调性

含义:

  • 对子串1中的每个元素a[i],在子串2中寻找到最小的元素b[j],满足a[i]+b[j] > x
    单调双指针

  • 初始化:
    i初始化在a[i]最小点,j初始化在b[j]最大点

  • 由于a[] b[] 的单调递增,在a[i]从小到大时,b[j]一定从大到小
    小的最小
    若a[0]对应b[1]
    大的更小
    则a[1]只需要从b[0]到b[1]中找满足a[1]+b[i]>x的最大b[i]

    换句话说,随着i指针向后移动,j指针必然是向前移动的

作用:

  • 由于对于每一个i指针右移,j指针在左移
    所以只需要遍历一次A序列和B序列
  • 去除了盲目枚举后,时间复杂度达到了O(n+m)
  • 单调双指针算法有一些二分的味道

写作步骤:

2步:

1. 初始化:一者最小,一者最大

  • i指针在a[0], j指针在b[m-1]

2. 移动方向:初始小的变大,初始大的变小

  • a[1] 对应 b[x] , 则 a[2] 对应 b[y]
    a[2] > a[1] 则 b[x] < b[y]

代码实现:

#include <iostream>
using namespace std;
const int N = 100010;
int n, m, x;
int a[N], b[N];

int main() {
    cin >> n >> m >> x;
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 0; i < m; i++) cin >> b[i];
    int i = 0, j = m-1;
    for (i = 0; i < n; i++) {
        while (a[i] + b[j] > x && j >= 0) j--;
        if (a[i] + b[j] == x) break;
    }
    cout << i << " " << j << endl;
    return 0;
}

代码误区:

1. 初始化:

  • 不论序列单调性:
    一者初始化为子串1中最小值,一者初始化为子串2中最大值
    初始最小的逐渐增大,初始最大的逐渐变小
  • 注意单调性变化,i取0还是取n-1,j取0还是取m-1

2. 边界问题:

  • 由于寻找的是a[i] + b[j] == x
    所以当a[i] + b[j] > x时,j - -
    j 停止- -时候含有两种情况:a[i] + b[j] < x 和 a[i] + b[j] == x
  • 若改成while(a[i] + b[j] >= x) j- -;
    停止循环时,只有a[i] + b[j] < x
    永远找不到答案

3. 单调双指针适用判断:

  • 双指针之所以具有单调性,有两方面因素:
    1. 序列具有单调性,或非递减,非递增性
    2. 双指针具有约束:
      arr[i] + arr[j] <= x;和一定,一者变大则另一者变小;
      若为差 arr[i] - arr[j] <= x; 差一定,虽是一者变大则另一者也变大,但也单调
    3. 不一定一者变大一者变小,只要随着一者单调变化,另一者也单调变化即可

本篇感想:

  • 花费时间有点多了,单调双指针其实就3句话
  1. 初始一者最大,一者最小
  2. 后来大者缩小,小者变大
  3. 注意边界问题
  • 看完本篇博客,恭喜已登《练气境-初期》
    练气期初阶
    距离登仙境不远了,加油 登仙境初期
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starnight531

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值