“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 18 天,点击查看活动详情”
41题(13分)
定义三元组(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)。
要求:
-
给出算法的基本设计思想。
-
根据设计思想,采用C语言或C++语言描述算法,关键之处给出注释。
-
说明你所设计算法的时间复杂度和空间复杂度。
前提
- 尽可能高效 那意思不高效就扣几分
- 按照升序存储
- 最小距离
除了算最小距离,我们还需要记录这三个元素。最简单的办法即取出每种组合,套公式来判断。
暴力解
typedef struct
{
int a,b,c;
int value;
} Triple;
Triple func(int S1[],int S2[],int S3[],int n1,int n2,int n3){
Triple T;
T.value=INT_MAX;
for(int i=0;i<n1;++i){
for(int j=0;j<n2;++j){
for(int k=0;k<n3;++k){
int D=(abs(S1[i]-S2[j])+abs(S1[i]-S3[k])+abs(S2[j]-S3[k]));
//abs是绝对值函数
if(D<T.value){
T.value=D;
T.a=S1[i];
T.b=S2[j];
T.c=S3[k];
}
}
}
}
return T;
}
时间复杂度为O(n³)
官方解析:可不看 直接暴力解7-8分省很多时间
42题(10分)
若任一个字符的编码都不是其他字符编码的前缀,则称这种编码具有前缀特性。现有某字符集(字符个数>2)的不等长编码,每个字符的编码均为二进制的 01序列,最长为L位,且具有前缀特性。请回答下列问题:
-
哪种数据结构适宜保存上述具有前缀特性的不等长编码?
-
基于你所设计的数据结构,简述从0/1串到字符串的译码过程
-
简述判定某字符集的不等长编码是否具有前缀特性的过程
解答:
-
使用一棵二叉树保存字符集中各字符的编码,每个编码对应于从根开始到达某叶结点的一条路径,路径长度等于编码位数,路径到达的叶结点中保存该编码对应的字符。
-
从左至右依次扫描 0/1 串中的各位。从根开始,根据串中当前位沿当前结点的左子指针或右子指针下移,直到移动到叶结点时为止。输出叶结点中保存的字符。然后从根开始重复这个过程,直到扫描到 0/1 串结束,译码完成。
-
二叉树既可用于保存各字符的编码,又可用于检测编码是否具有前缀特性。判定编码是否3具有前缀特性的过程,也是构建二叉树的过程。初始时,二叉树中仅含有根结点,其左子指针和右子指针均为空。
依次读入每个编码C,建立/寻找从根开始对应于该编码的一条路径,过程如下:
对每个编码,从左至右扫描C的各位,根据C的当前位(0或1)结点的指针(左子指针或右子指针)向下移动。当遇到空指针时,创建新结点,让空指针指向该新结点并继续移动。沿指针移动的过程中,可能遇到三种情况:
- 若遇到了叶结点(非根),则表明不具有前缀特性,返回。
- 若在处理 C的所有位的过程中,均没有创建新结点,则表明不具有前缀特性,返回
- 若在处理的最后一个编码位时创建了新结点,则继续验证下一个编码。
若所有编码均通过验证,则编码具有前缀特性。