一、题目描述
同一个数轴X上有两个点的集合A={A1, A2, ..., Am}和B={B1, B2, ..., Bn},Ai和Bj均为正整数,A、B已经按照从小到大排好序,A、B均不为空,给定一个距离R(正整数),列出同时满足如下条件的所有(Ai, Bj)数对:Ai <= Bj Ai, Bj之间的距离小于等于R 在满足1,2的情况下,每个Ai只需输出距离最近的Bj 输出结果按Ai从小到大的顺序排序。
二、输入输出描述
输入描述
- 第一行三个正整数m,n,R
- 第二行m个正整数,表示集合A
- 第三行n个正整数,表示集合B
输入限制:1<=R<=100000, 1<=n,m<=100000, 1<=Ai,Bj<=1000000000
输出描述
- 每组数对输出一行Ai和Bj,以空格隔开
三、示例
|----|---------------------------|
| 输入 | 4 5 5 1 5 5 10 1 3 8 8 20 |
| 输出 | 1 1 5 8 5 8 |
| 说明 | |
四、解题思路
- 核心思想
通过 "排序 + 双指针" 实现高效的元素匹配:先对setB排序,再用单向移动的指针遍历setB,为setA的每个元素找到满足 "≥valueA 且差值≤r" 的最小setB元素 ------ 核心是 "排序降维复杂度 + 双指针避免重复遍历"。
- 问题本质分析
- 表层问题:在两个数组中匹配满足 "B 元素≥A 元素且差值≤r" 的元素对,每个 A 元素匹配最小的符合条件的 B 元素;
- 深层问题:
- 无序数组的高效匹配:若
setB无序,需对每个 A 元素遍历整个 B(时间复杂度 O (m*n)),排序后可通过双指针将复杂度降至 O (m + n log n); - 单向指针的合理性:因
setB升序、setA遍历无顺序要求,指针仅需正向移动(已跳过的 B 元素均 < A 当前元素,无需回头)。
- 无序数组的高效匹配:若
- 核心逻辑
- 排序预处理:对
setB升序排序,保证元素有序,为双指针单向移动提供基础; - 双指针单向遍历:
indexB仅正向移动,避免对setB的重复遍历,降低时间开销; - 条件筛选:先找到
setB中≥valueA 的最小元素,再校验差值是否≤r,保证匹配的是 "最小且符合误差的 B 元素"。
-
步骤拆解
-
输入读取与初始化:
- 读取
setA长度、setB长度、误差范围r; - 读取
setA和setB的所有元素。
- 读取
-
预处理(排序):
- 对
setB进行升序排序,为双指针匹配做准备。
- 对
-
双指针匹配:
- 初始化
indexB=0(指向setB的起始位置); - 遍历
setA的每个元素valueA:- 移动
indexB,直到setB[indexB] ≥ valueA(或indexB越界); - 若未越界且差值≤r,输出元素对;否则跳过。
- 移动
- 初始化
-
结果输出:
- 逐行输出满足条件的元素对,无满足条件的则无输出。
五、代码实现
java
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 读取 m、n、r
int m = sc.nextInt();
int n = sc.nextInt();
int r = sc.nextInt();
int[] setA = new int[m];
int[] setB = new int[n];
// 读取数组 A
for (int x = 0; x < m; x++) {
setA[x] = sc.nextInt();
}
// 读取数组 B
for (int y = 0; y < n; y++) {
setB[y] = sc.nextInt();
}
// 调用匹配函数
matchPairs(setA, setB, r);
}
public static void matchPairs(int[] setA, int[] setB, int range) {
Arrays.sort(setB); // 先对 B 进行排序,确保双指针法可行
int indexB = 0; // 指向 B 中当前检查的元素
// 遍历数组 A 中的每个元素
for (int valueA : setA) {
// 移动 indexB,使其指向 >= valueA 的最小元素
while (indexB < setB.length && setB[indexB] < valueA) {
indexB++;
}
// 检查是否满足误差范围
if (indexB < setB.length && setB[indexB] - valueA <= range) {
System.out.println(valueA + " " + setB[indexB]);
}
}
}
}