华为OD机试 - 两个集合输出距离最近的数字 - 双指针(Java 2025 B卷 100分)

在这里插入图片描述

华为OD机试 2025B卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试(JAVA)真题(A卷+E卷+B卷+C卷+D卷)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

同一个数轴x有两个点的集合A={A1,A2,…,Am}和B={B1,B2,…,Bm},A(i)和B(i)均为正整数,A、B已经按照从小到大排序,AB均不为空,给定一个距离R,R是正整数。

列出同时满足以下条件的(A(i),B(j))数对:

1、A(i) < B(j)
2、A(i),B(i)之间距离小于等于R

在情况1、2的情况下每个A(i)只能输出距离最近的B(j)

输出结果按A(i)从小到大排序

二、输入描述

第一行输入三个正整数m n R
第二行m个正整数,表示集合A
第三行n个正整数,表示集合B

以空格隔开。

输入限制 1<=R<=100000, 1<=n,m<=100000, 1<= A(i),B(j) <= 1000000000

三、输出描述

每组数对输出一行 A(i)和B(j)

以空格隔开

四、测试用例

测试用例1

1、输入

3 4 5
1 6 10
2 7 11 15

2、输出

1 2
6 7
10 11

3、说明

A[0]=1: B[0]=2。2-1=1 <= 5。输出 (1,2)。

A[1]=6: B[1]=7。7-6=1 <= 5。输出 (6,7)。

A[2]=10: B[2]=11。11-10=1 <= 5。输出 (10,11)。

测试用例2

1、输入

3 3 10
10 20 30
1 2 3

2、输出

3、说明

A[0]=10: ptrB会遍历完B,但B中所有元素都小于10。ptrB到达B的末尾,主循环终止。没有输出。

五、解题思路

1、解题思路

问题要求从两个已排序的整数集合 A 和 B 中找出满足特定条件的数对 (A(i), B(j))。根据示例输出推断,条件是:1) 我们寻找的 B(j) 应该大于等于 A(i) (即 B(j) >= A(i)), 2) 它们之间的差 B(j) - A(i) 小于等于 R, 3) 对于每个 A(i),应选择那个使得差 B(j) - A(i) 最小的 B(j)。

由于集合 A 和 B 都已按从小到大排序,我们可以有效地使用双指针技术来寻找这些数对。一个指针 (ptrA) 遍历集合 A,另一个指针 (ptrB) 遍历集合 B。

2、具体步骤

初始化两个指针:ptrA = 0 (指向集合 A 的第一个元素) 和 ptrB = 0 (指向集合 B 的第一个元素)。
当 ptrA 没有遍历完集合 A 并且 ptrB 没有遍历完集合 B 时,执行以下循环:

获取集合 A 的当前元素 currentA = A[ptrA]。

调整 ptrB:向前移动 ptrB,直到 B[ptrB] 大于或等于 currentA (B[ptrB] >= currentA),或者 ptrB 到达了集合 B 的末尾。
这一步的目的是为 currentA 在 B 中找到第一个可能的候选配对元素。

检查 ptrB 是否越界:如果在上一步中 ptrB 到达了集合 B 的末尾,这意味着对于当前 currentA 以及 A 中所有后续的元素,在 B 中都不可能再找到大于或等于它们的元素了。因此,可以终止主循环。

检查距离条件:获取集合 B 的当前元素 currentB = B[ptrB]。计算它们之间的差值 diff = currentB - currentA。
如果 diff <= R:这表示找到了一个有效的数对 (currentA, currentB)。

因为 B 是排序的,并且 ptrB 指向的是第一个满足 B[j] >= currentA 的元素,所以这个 currentB 必然是使得差值 currentB - currentA 最小的那个。输出这个数对。

然后,将 ptrA 向后移动一位,去处理集合 A 中的下一个元素。 ii. 如果 diff > R:这表示 currentB 对于 currentA 来说太远了。由于集合 B 是排序的,ptrB 之后的所有 B 元素与 currentA 的差值将会更大或相等。

因此,当前的 currentA 不可能在 B 中找到符合条件的配对。将 ptrA 向后移动一位,去处理集合 A 中的下一个元素。ptrB 指针在此情况下不回溯,因为它所指向的 B[ptrB] 或其后的元素可能适用于 A 中下一个(更大的)元素。

当循环结束时,所有满足条件的数对都已经被输出。

六、Java算法源码

public class OdTest {
    public static void main(String[] args) {
        // 使用Scanner从控制台读取输入
        Scanner sc = new Scanner(System.in);

        // 读取第一行的三个正整数 m, n, R
        int m = sc.nextInt(); // 集合A的大小
        int n = sc.nextInt(); // 集合B的大小
        int R = sc.nextInt(); // 距离R

        // 读取第二行的m个正整数,表示集合A
        int[] A = new int[m]; // 初始化数组A
        for (int i = 0; i < m; i++) {
            A[i] = sc.nextInt(); // 读取A的每个元素
        }

        // 读取第三行的n个正整数,表示集合B
        int[] B = new int[n]; // 初始化数组B
        for (int i = 0; i < n; i++) {
            B[i] = sc.nextInt(); // 读取B的每个元素
        }

        // 双指针算法
        int ptrA = 0; // 指向集合A当前元素的指针
        int ptrB = 0; // 指向集合B当前元素的指针

        // 当两个指针都没有超出各自数组的边界时循环
        while (ptrA < m && ptrB < n) {
            // 移动ptrB,直到找到第一个 B[ptrB] >= A[ptrA] 的元素,
            // 或者ptrB到达数组B的末尾
            while (ptrB < n && B[ptrB] < A[ptrA]) {
                ptrB++; // ptrB向后移动
            }

            // 如果ptrB到达数组B的末尾,说明对于当前的A[ptrA]以及A中后续所有元素,
            // 在B中都找不到合适的(即大于或等于A[ptrA]的)元素了,因此跳出主循环
            if (ptrB == n) {
                break;
            }

            // 此时,我们有 B[ptrB] >= A[ptrA]
            // 检查它们之间的距离是否小于等于R
            if (B[ptrB] - A[ptrA] <= R) {
                // 条件满足:B[ptrB] >= A[ptrA] 且 B[ptrB] - A[ptrA] <= R
                // 由于集合B是排序的,且我们是从左到右推进ptrB以找到第一个B[j] >= A[i]的元素,
                // 所以当前的B[ptrB]是对于A[ptrA]来说,满足条件的、差值最小的B元素。
                System.out.println(A[ptrA] + " " + B[ptrB]); // 输出数对
                ptrA++; // 处理集合A中的下一个元素
            } else {
                // 条件不满足:B[ptrB] - A[ptrA] > R
                // 这意味着对于当前的A[ptrA],B[ptrB]以及B中后续的元素都太远了(因为B是排序的)。
                // 所以当前的A[ptrA]无法找到合适的配对。
                ptrA++; // 处理集合A中的下一个元素(ptrB不回溯,因为它可能对下一个A[ptrA+1]适用)
            }
        }
        // 关闭Scanner
        sc.close();
    }
}

七、效果展示

1、输入

4 5 5
1 5 5 10
1 3 8 8 20

2、输出

1 1
5 8
5 8

3、说明

A[0]=1: B中最小的>=1的元素是B[0]=1。1-1=0 <= 5。输出 (1,1)。

A[1]=5: B中(从ptrB当前位置开始)最小的>=5的元素是B[2]=8。8-5=3 <= 5。输出 (5,8)。

A[2]=5: B中(从ptrB当前位置开始)最小的>=5的元素是B[2]=8。8-5=3 <= 5。输出 (5,8)。

A[3]=10: B中(从ptrB当前位置开始)最小的>=10的元素是B[4]=20。20-10=10 > 5。无输出。

在这里插入图片描述


🏆下一篇:华为OD机试 - 简易内存池 - 逻辑分析(Java 2025 B卷 200分)

🏆本文收录于,华为OD机试(JAVA)真题(A卷+E卷+B卷+C卷+D卷)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

哪 吒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值