本题要求我们在三个非空整数集合中各取一个元素构成三元组,使其具有最小的距离。
题目描述
定义三元组 ( ( a , b , c ) ) ((a, b, c)) ((a,b,c)) 的距离 ( D = ∣ a − b ∣ + ∣ b − c ∣ + ∣ c − a ∣ ) (D = |a - b| + |b - c| + |c - a|) (D=∣a−b∣+∣b−c∣+∣c−a∣)。给定三个按升序排序的非空整数集合 ( S 1 , S 2 , S 3 ) (S_1, S_2, S_3) (S1,S2,S3),分别存储在数组 ( a , b , c ) (a, b, c) (a,b,c) 中。设计一个尽可能高效的算法,计算并输出所有可能三元组中的最小距离。
示例输入:
S1 = {-1, 0, 9}
S2 = {-25, -10, 10, 11}
S3 = {2, 9, 17, 30, 41}
示例输出:
最小距离:2
对应三元组:(9, 10, 9)
解题思路
暴力解法
暴力解法的核心思想是,遍历三个集合中所有可能的三元组 ( a , b , c ) (a, b, c) (a,b,c),计算其距离 D D D,并记录其中最小的距离值。具体步骤如下:
- 利用三重循环,分别遍历数组 a a a、 b b b、 c c c 中的每个元素。
- 对于每个三元组 ( ( a [ i ] , b [ j ] , c [ k ] ) ) ((a[i], b[j], c[k])) ((a[i],b[j],c[k])),计算其距离 ( D ) (D) (D)。
- 在所有三元组中找到最小的 ( D ) (D) (D) 及其对应的三元组。
代码实现:
#include <iostream>
#include <vector>
#include <climits>
#include <cmath>
#include <tuple>
using namespace std;tuple<vector<int>, int> brute_force(vector<int> a, vector<int> b, vector<int> c) {int minValue = INT_MAX;vector<int> ans;for (int ai : a) {for (int bi : b) {for (int ci : c) {int dist = abs(ai - bi) + abs(bi - ci) + abs(ci - ai);if (dist < minValue) {minValue = dist;ans = {ai, bi, ci};}}}}return {ans, minValue};
}int main() {vector<int> a = {-1, 0, 9};vector<int> b = {-25, -10, 10, 11};vector<int> c = {2, 9, 17, 30, 41};auto [result, minDist] = brute_force(a, b, c);cout << "最小距离: " << minDist << endl;cout << "对应三元组: ";for (int val : result) cout << val << " ";cout << endl;return 0;
}
优化解法:双指针法
通过双指针法可以大幅提升效率。由于三个集合都是按升序排列的,我们可以分别在三个集合中使用指针 ( p 1 , p 2 , p 3 ) (p1, p2, p3) (p1,p2,p3),从当前最小的数开始移动指针,以期更接近最小距离。具体思路:
- 初始化三个指针 ( p 1 , p 2 , p 3 ) (p1, p2, p3) (p1,p2,p3) 分别指向 ( a , b , c ) (a, b, c) (a,b,c) 的开头。
- 在每次迭代中计算 ( D ( a [ p 1 ] , b [ p 2 ] , c [ p 3 ] ) ) (D(a[p1], b[p2], c[p3])) (D(a[p1],b[p2],c[p3])) 并更新最小值。
- 在保证升序的前提下,移动当前最小值所在集合的指针。
代码实现:
#include <iostream>
#include <vector>
#include <climits>
#include <cmath>
using namespace std;vector<int> find(vector<int> a, vector<int> b, vector<int> c) {int minValue = INT_MAX;vector<int> ans;int q = 0, w = 0, r = 0;while(q < a.size() && w < b.size() && r < c.size()) {int t = abs(a[q] - b[w]) + abs(b[w] - c[r]) + abs(c[r] - a[q]);if (t < minValue) {ans = {a[q], b[w], c[r]};minValue = t;}if(a[q] < b[w] && a[q] <= c[r]) q++;else if(b[w] < c[r] && b[w] <= a[q]) w++;else r++;}return ans;
}
算法复杂度分析
- 暴力法: 复杂度为 ( O ( n 3 ) ) (O(n^3)) (O(n3)),其中 ( n ) (n) (n) 为每个集合的元素数。适用于集合元素较少的情况,但当集合规模较大时,性能较差。
- 双指针法: 复杂度为 O ( n ) O(n) O(n)。由于每次迭代移动一个指针,整体效率更高。
结论
在元素数较少时,暴力法简单直接;对于较大集合,应优先考虑双指针法来降低时间复杂度。此类算法思路在寻找多集合最小距离问题中广泛适用。