线性表练习之Example031-找出给定 3 个非空整数集合中所有可能的三元组中的最小距离

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性表练习之Example031-找出给定 3 个非空整数集合中所有可能的三元组中的最小距离相关的知识,希望对你有一定的参考价值。

Example031

原文链接:Example031

题目

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

分析

解法一分析

直接三重 for 循环,遍历完所有可能的三元组,然后计算最小距离。但时间复杂度非常高,为 O(n1*n2*n3)

解法二分析

算法的基本思想是,设置三个指针,分别用于遍历这三个数组。因为数组已有序,我们的算法实际上是找到一个尽可能接近的三元组,设三个数组分别为 S1、S2、S3,我们遍历使用的下标变量分别为x、y、z,则我们在 S1[x] 小于 S2[y]S3[z] 的时候,更新 x,其它两个下标变量 y 和 z 更新同理,同时,对于每一组三个下标变量,我们计算其对应元素的距离值,然后与上一次的距离值比较,并取其中较小的一个作为更新的距离值。时间复杂度为 O(n1+n2+n3)

参考资料:

图解

略。

C实现

解法一核心代码:

/**
 * 求一个数的绝对值
 *
 * @param num 指定整数,可以是正数,也可以是负数
 * @return 绝对值
 */
int abs(int num) 
    if (num < 0) 
        return -num;
     else 
        return num;
    


/**
  * 求所有可能的三元组中的最小距离
  *
  * @param S1 第一个非空整数集合
  * @param n1 第一个数组的长度
  * @param S2 第二个非空整数集合
  * @param n2 第二个数组的长度
  * @param S3 第三个非空整数集合
  * @param n3 第三个数组的长度
  * @return 三元组中的最小距离
  */
int minDistance(int S1[], int n1, int S2[], int n2, int S3[], int n3) 
    // 变量,记录 S1 中的元素
    int a = S1[0];
    // 变量,记录 S2 中的元素
    int b = S2[0];
    // 变量,记录 S3 中的元素
    int c = S3[0];
    // 变量,记录三元组中的最小距离
    int minD = abs(a - b) + abs(b - c) + abs(c - a);

    // 三重 for 循环遍历三个非空整数集合
    for (int x = 0; x < n1; x++) 
        for (int y = 0; y < n2; y++) 
            for (int z = 0; z < n3; z++) 
                // 计算由 S1[x]、S2[y] 和 S3[z] 组成的三元组的最小距离
                int min = abs(S1[x] - S2[y]) + abs(S2[y] - S3[z]) + abs(S3[z] - S1[x]);
                // 如果比 minD 更小,那么更新
                if (min < minD) 
                    minD = min;
                    a = S1[x];
                    b = S2[y];
                    c = S3[z];
                
            
        
    
    printf("最小距离为 %d,相应的三元组为 (%d, %d, %d)。", minD, a, b, c);
    return minD;

解法二核心代码:

/**
 * 判断 a 是否是三个数中的最小值
 *
 * @param a 第一个数
 * @param b 第二个数
 * @param c 第三个数
 * @return 如果 a 是三个数中的最小值则返回 1,否则返回 0
 */
int minA(int a, int b, int c) 
    if (a <= b && a <= c) 
        return 1;
    
    return 0;


/**
 * 求一个数的绝对值
 *
 * @param num 指定整数,可以是正数,也可以是负数
 * @return 绝对值
 */
int abs(int num) 
    if (num < 0) 
        return -num;
     else 
        return num;
    


/**
 * 求所有可能的三元组中的最小距离
 *
 * @param S1 第一个非空整数集合
 * @param n1 第一个数组的长度
 * @param S2 第二个非空整数集合
 * @param n2 第二个数组的长度
 * @param S3 第三个非空整数集合
 * @param n3 第三个数组的长度
 * @return 三元组中的最小距离
 */
int minDistance(int S1[], int n1, int S2[], int n2, int S3[], int n3) 
    int x = 0, y = 0, z = 0;
    // 变量,记录三元组中的最小距离
    int minD = abs(S1[x] - S2[y]) + abs(S2[y] - S3[z]) + abs(S3[z] - S1[x]);

    while (x < n1 && y < n2 && z < n3) 
        int min = abs(S1[x] - S2[y]) + abs(S2[y] - S3[z]) + abs(S3[z] - S1[x]);
        if (min < minD) 
            minD = min;// 更新最小距离
        
        if (minA(S1[x], S2[y], S3[z]) == 1) // 如果 S1[x] 是三个数中的最小值,则 x 前进
            x++;
         else if (minA(S2[y], S3[z], S1[x]) == 1) // 如果 S2[y] 是三个数中的最小值,则 y 前进
            y++;
         else // 如果 S3[z] 是三个数中的最小值,则 z 前进
            z++;
        
    

    return minD;

完整代码:

#include <stdio.h>

/**
 * 求一个数的绝对值
 *
 * @param num 指定整数,可以是正数,也可以是负数
 * @return 绝对值
 */
int abs(int num) 
    if (num < 0) 
        return -num;
     else 
        return num;
    


/**
  * 求所有可能的三元组中的最小距离
  *
  * @param S1 第一个非空整数集合
  * @param n1 第一个数组的长度
  * @param S2 第二个非空整数集合
  * @param n2 第二个数组的长度
  * @param S3 第三个非空整数集合
  * @param n3 第三个数组的长度
  * @return 三元组中的最小距离
  */
int minDistance(int S1[], int n1, int S2[], int n2, int S3[], int n3) 
    // 变量,记录 S1 中的元素
    int a = S1[0];
    // 变量,记录 S2 中的元素
    int b = S2[0];
    // 变量,记录 S3 中的元素
    int c = S3[0];
    // 变量,记录三元组中的最小距离
    int minD = abs(a - b) + abs(b - c) + abs(c - a);

    // 三重 for 循环遍历三个非空整数集合
    for (int x = 0; x < n1; x++) 
        for (int y = 0; y < n2; y++) 
            for (int z = 0; z < n3; z++) 
                // 计算由 S1[x]、S2[y] 和 S3[z] 组成的三元组的最小距离
                int min = abs(S1[x] - S2[y]) + abs(S2[y] - S3[z]) + abs(S3[z] - S1[x]);
                // 如果比 minD 更小,那么更新
                if (min < minD) 
                    minD = min;
                    a = S1[x];
                    b = S2[y];
                    c = S3[z];
                
            
        
    
    printf("最小距离为 %d,相应的三元组为 (%d, %d, %d)。", minD, a, b, c);
    return minD;


int main() 
    int A[] = -1, 0, 9;
    int an = 3;
    int B[] = -25, -10, 10, 11;
    int bn = 4;
    int C[] = 2, 9, 17, 30, 41;
    int cn = 5;

    // 调用函数
    minDistance(A, an, B, bn, C, cn);

执行结果:

最小距离为 2,相应的三元组为 (9, 10, 9)。

Java实现

解法一核心代码:

    /**
     * 求所有可能的三元组中的最小距离
     *
     * @param S1 第一个非空整数集合
     * @param n1 第一个数组的长度
     * @param S2 第二个非空整数集合
     * @param n2 第二个数组的长度
     * @param S3 第三个非空整数集合
     * @param n3 第三个数组的长度
     * @return 三元组中的最小距离
     */
    public static int minDistance(int S1[], int n1, int S2[], int n2, int S3[], int n3) 
        // 变量,记录 S1 中的元素
        int a = S1[0];
        // 变量,记录 S2 中的元素
        int b = S2[0];
        // 变量,记录 S3 中的元素
        int c = S3[0];
        // 变量,记录三元组中的最小距离
        int minD = abs(a - b) + abs(b - c) + abs(c - a);

        // 三重 for 循环遍历三个非空整数集合
        for (int x = 0; x < n1; x++) 
            for (int y = 0; y < n2; y++) 
                for (int z = 0; z < n3; z++) 
                    // 计算由 S1[x]、S2[y] 和 S3[z] 组成的三元组的最小距离
                    int min = abs(S1[x] - S2[y]) + abs(S2[y] - S3[z]) + abs(S3[z] - S1[x]);
                    // 如果比 minD 更小,那么更新
                    if (min < minD) 
                        minD = min;
                        a = S1[x];
                        b = S2[y];
                        c = S3[z];
                    
                
            
        
        System.out.println("最小距离为 " + minD + ",相应的三元组为 (" + a + ", " + b + ", " + c + ")。");
        return minD;
    

    /**
     * 求一个数的绝对值
     *
     * @param num 指定整数,可以是正数,也可以是负数
     * @return 绝对值
     */
    private static int abs(int num) 
        if (num < 0) 
            return -num;
         else 
            return num;
        
    

解法二核心代码:

    /**
     * 求所有可能的三元组中的最小距离
     *
     * @param S1 第一个非空整数集合
     * @param n1 第一个数组的长度
     * @param S2 第二个非空整数集合
     * @param n2 第二个数组的长度
     * @param S3 第三个非空整数集合
     * @param n3 第三个数组的长度
     * @return 三元组中的最小距离
     */
    public static int minDistance(int S1[], int n1, int S2[], int n2, int S3[], int n3) 
        int x = 0, y = 0, z = 0;
        // 变量,记录三元组中的最小距离
        int minD = abs(S1[x] - S2[y]) + abs(S2[y] - S3[z]) + abs(S3[z] - S1[x]);

        while (x < n1 && y < n2 && z < n3) 
            int min = abs(S1[x] - S2[y]) + abs(S2[y] - S3[z]) + abs(S3[z] - S1[x]);
            if (min < minD) 
                minD = min;// 更新最小距离
            
            if (minA(S1[x], S2[y], S3[z]) == 1) // 如果 S1[x] 是三个数中的最小值,则 x 前进
                x++;
             else if (minA(S2[y], S3[z], S1[x]) == 1) // 如果 S2[y] 是三个数中的最小值,则 y 前进
                y++;
             else // 如果 S3[z] 是三个数中的最小值,则 z 前进
                z++;
            
        

        return minD;
    

    /**
     * 判断 a 是否是三个数中的最小值
     *
     * @param a 第一个数
     * @param b 第二个数
     * @param c 第三个数
     * @return 如果 a 是三个数中的最小值则返回 1,否则返回 0
     */
    private static int minA(int a, int b, int c) 
        if (a <= b && a <= c) 
            return 1;
        
        return 0;
    

    /**
     * 求一个数的绝对值
     *
     * @param num 指定整数,可以是正数,也可以是负数
     * @return 绝对值
     */
    private static int abs(int num) 
        if (num < 0) 
            return -num;
         else 
            return num;
        
    

完整代码:

public class Test 
    public static void main(String[] args) 
        int[] A = new int[]-1, 0, 9;
        int[] B = new int[]-25, -10, 10, 11;
        int[] C = new int[]2, 9, 17, 30, 41;

        // 调用函数
        minDistance(A, A.length, B, B.length, C, C.length);
    

    /**
     * 求所有可能的三元组中的最小距离
     *
     * @param S1 第一个非空整数集合
     * @param n1 第一个数组的长度
     * @param S2 第二个非空整数集合
     * @param n2 第二个数组的长度
     * @param S3 第三个非空整数集合
     * @param n3 第三个数组的长度
     * @return 三元组中的最小距离
     */
    public static int minDistance(int S1[], int n1, int S2[], int n2, int S3[], int n3) 
        // 变量,记录 S1 中的元素
        int a = S1[0];
        // 变量,记录 S2 中的元素
        int b = S2[0];
        // 变量,记录 S3 中的元素
        int c = S3[0];
        // 变量,记录三元组中的最小距离
        int minD = abs(a - b) + abs(b - c) + abs(c - a);

        // 三重 for 循环遍历三个非空整数集合
        for (int x = 0; x < n1; x++) 
            for (int y = 0; y < n2; y++) 
                for (int z = 0; z < n3; z++) 
                    // 计算由 S1[x]、S2[y] 和 S3[z] 组成的三元组的最小距离
                    int min = abs(S1[x] - S2[y]) + abs(S2[y] - S3[z]) + abs(S3[z] - S1[x]);
                    // 如果比 minD 更小,那么更新
                    if (min < minD) 
                        minD = min;
                        a = S1[x];
                        b = S2[y];
                        c = S3[z];
                    
                
            
        
        System.out.println("最小距离为 " + minD + ",相应的三元组为 (" + a + ", "以上是关于线性表练习之Example031-找出给定 3 个非空整数集合中所有可能的三元组中的最小距离的主要内容,如果未能解决你的问题,请参考以下文章

线性表练习之Example048-判断一个单链表是否有环,如果有则找出环的入口点并返回,否则返回 NULL

线性表练习之Example019-删除单链表中所有介于给定两个值之间的元素的元素

线性表练习之Example047-找出由 str1 和 str2 所指向两个链表共同后缀的起始位置

线性表练习之Example013-只用一个变量来求个位数字组成的正整数数组中的最小值

线性表练习之Example039-删除循环单链表中的所有最小值节点直至链表为空

线性表练习之Example004-将顺序表中所有元素逆置