题目描述
求A[i] + B[j] == k 的 (i , j) 对
样例
输入
4 5 6
1 2 4 7
3 4 6 8 9
输出
1 1
算法1
(双指针) $O(n)$
i从 0开始 从前往后遍历
j从 m - 1开始 从后向前遍历
和纯暴力的$O(n^2)$ 算法的区别就在于
j指针不会回退
C++ 代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
int n, m, k;
int a[N], b[N];
#define read(x) scanf("%d",&x)
int main()
{
read(n), read(m), read(k);
for (int i = 0; i < n; i ++ ) read(a[i]);
for (int i = 0; i < m; i ++ ) read(b[i]);
for (int i = 0, j = m - 1; i < n; i ++) {
while(j >= 0 && a[i] + b[j] > k) j --;
if(j >= 0 && a[i] + b[j] == k) printf("%d %d\n", i, j);
}
return 0;
}
和纯暴力的
O(n^2^)
算法的区别就在于####
j
指针不会回退醍醐灌顶
真的是啊!
谢谢你科比
确实
谢谢你劳达
谢谢牢大
二分
强,谢谢佬
想问一下 为什么最后不能是b[r]==y啊
l
和r
都可以,是一样的。最后区间里只剩一个数,l
和r
都指向这个数想不到在题解代码里能看到金牌学长hh
%%%
相同的思路
哈希
其实在输入b[i]的时候就可以判断了
求问:为什么不能双指针从同一边开始啊
for(int i = 0,j = 0;i < n;i )
{
while(j < m && A[i] + B[j] < x)
{
j ;
}
if(j < m && A[i] + B[j] == x) cout<<i<<” “<<j<<endl;
}
可以想想i前进控制增j回退控制减,如果两个都前进都是控制增了
这里的双指针就是递增遍历a[i],然后a[i]递增过头了就用j回退把sum重新减小
同时双指针同一边开始会出现漏解的情况
有没有大佬解答下,为什么最后的if判断里面要加j>=0哇?while循环的条件不是已经保证了吗?
妙
有个问题,貌似有点错误,就是取j的时候,算出了大于j的最大整数,可能b[j-2],b[j-1],b[j]这三个的数值相等,但是按照题意只输出了一个j,但是测试点好像没给出来
题目要求唯一解
妙啊 不是等于就是小于
感觉加个break更顺眼
请问为什么A[i] + B[j] != x就会没有输出,>x就是对的呢
在顺序排列下不应该是等价的吗
<x 也是不等于啊
不不不 不等于的意思是只要不等于就会一直j–
厉害
顶顶大佬!
话说还能再抠点 A[i+1]必比A[i]大 要实现A+B = x 必然有 j ‘ <= j
所以i向下走一位,j从当前位置出发就行了(
int ans = m - 1;
for (int i = 0, j = ans; i < n; i++)
{
while (j >= 0 && A[i] + B[j] > x) ans = –j;
if (A[i] + B[j] == x)cout << i <<’ ‘<< j;
}
改成这样也能做(
read(x)我太喜欢了
#
可是cin更简单hhh
纯c是信仰
我j从头开始为什么不能过?边界都是一样的 输出为空
因为j指针会一直往后走,按照你的代码,把样例走一下,
1 2 4 7
3 4 6 8 9
你会发现当j指到6时,i才会指到2,然后i不管是什么和j指的6相加都会大于6,所以不会输出
恍然大悟
补充一点:除了j指针不会回退 判断重复元素的方法也是很大的一个优化
###很棒
为什么我用二分输出是空的啊?编译可以通过
模板写错了哦,由于
res < b[mid]
,所以l
不能取到mid
, 所以是r = mid - 1
, 用第二个模板噢,我粗心了,谢谢
其实不一定一定要用第二个板子,看见你的问题,我刚刚两个mid取法都去试着用了一下,发现其实都可以写,然后这个其实还可以控制如果找不到res,我最后的l会取到哪个位置,只是判断不一样