当前位置: 首页 > backend >正文

2020年_408统考_数据结构41题

题目

定义三元组 (a, b, c)(其中 a, b, c 均为正数)的距离 D = |a - b| + |b - c| + |c - a| 。给定 3 个非空整数集合 S1 、S2 和 S3 ,按升序分别存储在 3 个数组中。请设计一个尽可能高效的算法,计算并输出所有可能的三元组 (a, b, c)(a ∈ S1, b ∈ S2, c ∈ S3)中的最小距离。例如 S1 = {- 1, 0, 9} ,S2 = {-25, -10, 10, 11} ,S3 = {2, 9, 17 , 30, 41} ,则最小距离为 2 ,相应的三元组为 (9 , 10, 9) 。要求:

  1. 给出算法的基本设计思想。
  2. 根据设计思想, 采用 C 或 C++ 语言描述算法, 关键之处给出注释。
  3. 说明你所设计算法的时间复杂度和空间复杂度。

1.算法基本设计思想

先写出初始数组

在这里插入图片描述
D = |a - b| + |b - c| + |c - a|,这道题的最终结果就是求出 D 的最小值,不妨先画出数轴来帮助我们理解一下这到底是什么意思,这里以S1[2],S2[2],S3[0]为例:

红色代表S1, 绿色代表S2,蓝色代表S3
在这里插入图片描述

在这里插入图片描述
如图:开始推算,|a-b|=1 |b-c|=8 |c-a|=7 相加得出 d = 16,由此得出 D = (最右端 - 最左端 )*2,所以就要求 左端点的值尽可能的大 ,右端点的值尽可能的小(由于数组是递增的,当前选定的右端点一定为最小值),在数轴中小的数在最左边,所需要确认一个a,b,c中的最小值来做左端点,不断的去匹配,例如:
(题目中要求a,b,c大于0,我们示范时忽略这个条件)
在这里插入图片描述
D=(2-(-25))*2 = 54
由于 a.b.c中 b的值最小,所以b做了左端点,继续匹配,b的值是当前的最小值(需要不断偏移左端点,使其变大),存在于S2中,所以更改 b 为 -10
在这里插入图片描述
D=(2-(-10))*2 = 24

继续重复 ,更新b的值为10
在这里插入图片描述
D=(10-(-1))* 2 = 22

此时,左端点变为了 a ,将其更新
在这里插入图片描述
D=(10-0)*2 = 20

继续:
在这里插入图片描述
此时,左端点变为了 c ,更新:

在这里插入图片描述
得出了答案,D=(10-9)*2此时继续更新,同时更新 a,c,发现 a 最高到 9 不能再向后偏移了,也就是说下次如果还是当前左端点最小的话,左端点的值就定死了,只能不断更新右端点(如果按照此例子来解释,就是 当前a已经是 a,b,c中最小的了,由于数组是递增的,那么b和c之后的值一定会更大,不断的更新右端点 )不断向前,最终导致D的值不断增大,继续移动 a 的指针会越界,因此只能移动其他最小值的指针,当至少有一个到达对应数组的末尾时,遍历必须终止:
在这里插入图片描述
D=(17-9)*2 = 16

下来,根据数轴来推断,那么该如何将D变小呢?

推论

当 :我们确定

  • 左端点朝右移,已知其余两个点的值,通过公式D = |a - b| + |b - c| + |c - a|
  • 为什么知道其余两个点的值?
    -当我们不断的移动当前 a (S1 [i])、b (S2 [j])、c (S3 [k]) 中的最小值,若最小值所在数组的指针未越界,则移动该指针,会出现三种情况
    1. 更新的左端点的值还是最小值,其余两个点的值不变,由于数组递增,获取的新左端点一定比之前的左端点值大
    2. 更新的左端点的值在原来右端点和当前左节点(已经替换)之间,当前左节点的值,在未更新前就已经知道,由于更新过后的左端点的值比原来左端点的值大,例如:
    在这里插入图片描述
    更新的左端点的值要在原来右端点和新的左端点(2)之间,所以取更新的左端点为 3
    在这里插入图片描述
    重新获取当前左端点,为 2 ,由此可知,获取的当前左端点的值一定是大于上一个左端点,但是右端点还是没有变,所以依旧可以确定三个点的位置,通过公式得出D依旧是减小的
    3. 更新的左端点的值在原来右端点之后,如图;
    在这里插入图片描述
    按照解释,更新的值应从 -10 更新为大于 5 的值
    - 如果更新的值 等于 17(5+2+10) ,那么D值不变
    - 如果更新的值 小于 17 ,那么D值减小
    - 如果更新的值 大于 17 ,那么D的值增大
    我们每次计算D的之后,都会令其和之前的D比较,发现小于之前的D,更新答案,就避免了这种,还没有遍历完D就增大的情况

算法思路

通过遍历数组,从 0 索引开始,同时获取S1,S2, S3的元素,通过不断的比较,来确定左端点,然后不断的更新最小的数,不断更新左节点,不断的计算D,以获得最终答案

代码实现;

/*************************************************************************> File Name: solve.cpp> Author:> Mail:> Created Time:************************************************************************//************************************************************************** 题目:计算三个有序数组中元素组成的三元组的最小距离* 算法思路:* 1. 利用三指针法遍历三个有序数组* 2. 每次计算当前三个元素的距离 D = |a-b| + |b-c| + |c-a|* 3. 选择三个元素中最小的那个元素,前进其所在数组的指针* 4. 重复上述过程直到任一数组遍历完毕* 5. 在整个过程中记录最小距离************************************************************************/
#include <iostream>
#include <cstdlib>
#include <queue>
using namespace std;int min_num(int a, int b, int c) {if (a > b) swap(a, b);if (a > c) swap(a, c);return a;
}int func(queue<int> que1, queue<int> que2, queue<int> que3) {int ans = 0x3f3f3f3f;//设置answhile (!que1.empty() && !que2.empty() && !que3.empty()){int a = que1.front(), b = que2.front(), c = que3.front();int D = abs(a - b) + abs(b - c) + abs(c - a);ans = min(ans, D);int new_left = min_num(a, b, c);if (a == new_left) que1.pop();if (b == new_left) que2.pop();if (c == new_left) que3.pop();//操作完毕之后已经获得了最新的指针位置}return ans;
}int main() {int m, n, k, x;queue<int> que1, que2, que3;cin >> m >> n >> k;for (int i = 0; i < m; i++) {cin >> x;que1.push(x);}for (int i = 0; i < n; i++) {cin >> x;que2.push(x);}for (int i = 0; i < k; i++) {cin >> x;que3.push(x);}cout << func(que1, que2, que3) << endl;return 0;
}

这个算法的时间复杂度为:

时间复杂度:

empty(): O(1) - 队列判断是否为空是常数时间

front(): O(1) - 获取队首元素是常数时间

pop(): O(1) - 弹出队首元素是常数时间

min_num() 中的 swap(): O(1) - 交换两个整数值是常数时间

abs(): O(1) - 绝对值计算是常数时间

min(): O(1) - 比较两个数是常数时间

循环最多执行 (m + n + k) 次

时间复杂度:O(m + n + k)

空间复杂度

空间复杂度:O(m + n + k)

由于是值传递,创建了三个队列的副本

每个队列分别需要 O(m)、O(n)、O(k) 空间

因此总空间复杂度为 O(m + n + k)

http://www.xdnf.cn/news/20043.html

相关文章:

  • #数据结构----2.1线性表
  • 谈谈你对ThreadLocal的理解
  • 2025数学建模国赛高教社杯B题思路代码文章助攻
  • C++字符串字符替换程序
  • 【系统架构设计(16)】软件架构设计二:软件架构风格:构建系统的设计模式与选择指南
  • 学习机器学习能看哪些书籍
  • 白盒审计绕过
  • [bat-cli] docs | 控制器
  • 网络计算工具ipcalc详解
  • C++11 智能指针的使⽤及其原理
  • A股大盘数据-20250904分析
  • SAP HANA Scale-out 01:表分布
  • Vue.js 面试题集合
  • 钉钉 AI 深度赋能制造业 LTC 全流程:以钉钉宜搭、Teambition 为例
  • 【C++】计算地球上两个地理坐标点之间的距离和航向角
  • 期货市场上证50期权沪深300期权中证500期权那个好?
  • git命令行打patch
  • 支付域——支付与交易概念
  • 龙虎榜——20250904
  • 深度剖析:智能驾驶到底给2025带来了什么
  • 用服务器搭 “私人 AI 助手”:不用联网也能用,支持语音对话 / 文档总结(教程)
  • Hoppscotch:开源轻量API测试工具,秒启动高效解决临时接口测试需求
  • git基础命令 git基础操作
  • PyTorch DDP 随机卡死复盘
  • < 自用文 OS 有关 > (续)发现正在被攻击 后的自救 Fail2ban + IPset + UFW 工作流程详解
  • 十四、STM32-----低功耗
  • 【前端教程】JavaScript DOM 操作案例解析与代码优化
  • 不用服务器也能监控网络:MyIP+cpolar让中小企业告别昂贵方案
  • 【全网最全】《2025国赛/高教杯》C题 思路+代码python和matlab+文献 一到四问 退火算法+遗传算法 NIPT的时点选择与胎儿的异常判定
  • Qt 系统相关 - 1