一、题目
定义三元组(a, b, c)(其中a, b, c均为正数)的距离D=|a-b| + |b-c| + |c-a|。给定三个非空整数集合S1、S2和S3,按升序分别存储在3个数组中。设计一个尽可能高效的算法,计算并输出所有可能的三元组(a, b, c)(a∈S1, b∈S2, c∈S3)中的最小距离。要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,采用 C 或 C++语言描述算法,关键之处给出注释。
(3)说明你所设计算法的时间复杂度和空间复杂度。
二、解答
(1)通过三个队列每次出队最小值的策略;
(2)C++实现:
// -*- coding: utf-8 -*-
// @ Date : 2021/5/20 13:14
// @ Author : RichardLau_Cx
// @ file : Richard.cpp
// @ IDE : Dev-C++
// @ Source : Data_Structure
#include <iostream>
#include <cstdlib>
#include <queue>
using namespace std;
int minimum(int a, int b, int c)
{ // 返回三个值中最小的那个值
if (a <= b && a <= c)
{
return a;
}
else if (b <= a && b <= c)
{
return b;
}
else if (c <= a && c <= b)
{
return c;
}
else return 0;
}
int func(queue<int> que1, queue<int> que2, queue<int> que3)
{ /** 核心功能算法部分
* *quei: 分别传入三个不同的队列元素,分别对于题目中的a, b, c
*/
// 获取元素个数
int len1, len2, len3;
len1 = que1.size();
len2 = que2.size();
len3 = que3.size();
// cout << que1.size() << que2.size() << que3.size() << endl; // 查看队列长度(元素个数)
/*
for (int i=0; i < len1; i++)
{ // 队列查看
cout << que1.front() << ' '; // 返回队首元素的值,但不删除该元素
que1.pop(); // 删除队列首元素但不返回其值
}
*/
int min = 99; // 初始化最小值
int temp; // 中间临时值
int q1, q2, q3; // 为了表示简洁,对每轮元素名进行替换
while(que1.size() != 0 && que2.size() != 0 && que3.size() != 0)
{
q1 = que1.front();
q2 = que2.front();
q3 = que3.front();
temp = abs(q1 - q2) + abs(q2 - q3) + abs(q3 - q1);
/*
// 由于switch 语句中的 expression 是一个常量表达式,必须是一个整型或枚举类型。所以改用if-else语句
switch(minimum(q1, q2, q3))
{
case q1: que1.pop(); break;
case q2: que2.pop(); break;
case q3: que3.pop(); break;
}
*/
if(minimum(q1, q2, q3) == q1) que1.pop();
else if (minimum(q1, q2, q3) == q2) que2.pop();
else if (minimum(q1, q2, q3) == q3) que3.pop();
else return 0;
if(temp < min)
{
min = temp;
}
}
return min;
}
int main()
{
// 定义三个非空整数集
int set1[] = {-1, 0, 9};
int set2[] = {-25, -10, 10, 11};
int set3[] = {2, 9, 17, 30, 41};
/* (也可采用循环赋值)
for (int i=0; i < n; i++)
{
cin >> set1[i];
}
*/
// 获取集合元素个数
int len1, len2, len3;
len1 = sizeof(set1) / sizeof(int);
len2 = sizeof(set2) / sizeof(int);
len3 = sizeof(set3) / sizeof(int);
// cout << len1 << len2 << len3 << endl; // 查看集合长度(元素个数)
/*
for (int i=0; i < len1; i++)
{ // 集合数据测试
cout << set1[i] << ' ';
}
*/
// 定义三个队列
queue<int> que1, que2, que3;
// 将三个集合入三个队列
for (int i=0; i < len1; i++)
{
que1.push(set1[i]);
}
for (int i=0; i < len2; i++)
{
que2.push(set2[i]);
}
for (int i=0; i < len3; i++)
{
que3.push(set3[i]);
}
/*
for (int i=0; i < len2; i++)
{ // 队列查看
cout << que2.front() << ' '; // 返回队首元素的值,但不删除该元素
que2.pop(); // 删除队列首元素但不返回其值
}
*/
cout << "三元组两两最小间距和为:" << func(que1, que2, que3);
return 0;
}
(3)时空复杂度(针对核心功能算法而言):
- 时间复杂度:一个for循环,T(n) = O(n);
- 空间复杂度:辅助空间均为离散常量(不包括队列),S(n) = O(1)。
三、测试数据
// 定义三个非空整数集
int set1[] = {-1, 0, 9};
int set2[] = {-25, -10, 10, 11};
int set3[] = {2, 9, 17, 30, 41};