2020年专业408的算法题

1 题目

请添加图片描述

2 解法一(朴素算法:三重for循环)

思路:
暴力求解所有可能

#include<cstdio>
#include<climits>
#include<cmath>
#include<string.h>
#include<iostream>

int main(){
//S1={-1,0,9},S2={-25,-10,10,11},S3={2,9,17,30,41}
	int S1[] = {-1,0,9};
	int S2[] = {-25, -10, 10, 11};
	int S3[] = {2, 9, 17, 30, 41};
	int res[3];
	//初始化
	memset(res, 0, sizeof(res));
	//计算长度
	int extent1 = sizeof(S1)/sizeof(*S1);
	int extent2 = sizeof(S2)/sizeof(*S2);
	int extent3 = sizeof(S3)/sizeof(*S3);
	//定义int最大值,用于向下比较
	int minLength = INT_MAX; 
	for(int i = 0;i < extent1;i++){
		for(int j = 0;j < extent2;j++){
			for(int k = 0;k < extent3;k++){
				int tempLength = std::abs(S1[i] - S2[j]) + std::abs(S2[j]- S3[k]) + std::abs(S3[k] - S1[i]);
				if(tempLength < minLength){
					minLength = tempLength;
					res[0] = S1[i];
					res[1] = S2[j];
					res[2] = S3[k];
				}
			}
		}
	}
	
	for(auto i:res){
		std::cout<<i<<std::endl;
	}
	
     printf("MinLength is %d", minLength);	
	
	return 0;
}

时间复杂度: O ( e x t e n t 1 ∗ e x t e n t 2 ∗ e x t e n t 3 ) O(extent1*extent2*extent3) O(extent1extent2extent3)
空间复杂度: O ( 1 ) O(1) O(1)

3 解法二(较优解:二重循环+指针后移)

思路:二重循环扫描a、b,而c数组指针向右移(不回头)。

即:数组A、B、C的长度分别为l、m、n,双重循环枚举a、b,对数组C设置变量k存储数组下标不断后移,初始k=0,只要移动后的D更小(即c不是最右边的点;为中间点时,移动后距离大小不变;为最左边点时,移动后距离变小),就选择后移,然后对每一组a、b、c求出对应的距离D,并从中选出最小的距离。

三种情况(下面三种情景,a和b可以互换):
a b c 【c右移,距离只会变大】
a c b【c右移,距离不变】
c a b 【c右移,距离变小】

void ans(int A[], int B[], int C[], int m, int n, int l){
    int D_min = INT_MAX, D;
    int k = 0;//数组C下标初始为0
    for (int i = 0; i < n; ++i) {枚举a、b
        for (int j = 0; j < m; ++j) {
            D = DD(A[i], B[j], C[k]);
            while(k < l - 1 && DD(A[i], B[j], C[k + 1]) < D){//只有在c为最左边的点时,才右移 
                D = DD(A[i], B[j], C[++k]); //更新下标k和距离D
            }
            if(D < D_min) D_min = D;//更新D_min值
        }
    }
    std::cout<<D_min;
}

时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)

4 解法三(较优解:一重循环+两折半查找)

思路:一重循环扫描a,两轮折半查找b、c。

即:枚举a,两次折半查找b、c,找到最接近a的b和c值,然后判断<A[i], B[j], C[k]>、<A[i], B[j+1], C[k]>、<A[i], B[j], C[k+1]>、<A[i], B[j+1], C[k+1]>哪种情况D最小即可。

//伪代码
int BinarySearch(int A[], L, R, x){
    int mid;
    while(L < R){
        mid = (L + R)/2;
        if(x <= A[mid]) R = mid;
        else L = mid + 1;
    }
    return L;
}

void ans(int A[],n ,B[], m, C[], l){
	int D_min = Maxint, D;
	int k, l = 0;
	for(int i = 0; i < n;i++){
		j = BinarySearch(B[], 0, m, A[i]);
		k = BinarySearch(C[], 0, m, A[i]);
		//对A[i]、B[j-1]或B[j]或B[j+1],C[k-1]或C[k]或C[k+1]>排列组合求出最小的D并与D_min比较更新
	}
	cout<<D_min;
}

时间复杂度: O ( n ∗ l o n g m ∗ l o n g l ) O(n*longm*longl) O(nlongmlongl)
空间复杂度: O ( n ∗ l o g 2 n ) O(n*log^2n) O(nlog2n)

5 解法四(最优解:技巧——贪心+三指针后移)

思路(摘自百度文档):
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
实现代码:

#include<cstdio>
#include<climits>
#include<cmath>
#include<string.h>
#include<iostream>

#define xIsMin(x, y, z) (((x) <= (y)) && ((x) <= (z)))

void ans(int S1[], int S2[], int S3[], int extent1, int extent2, int extent3){
    int res[3];
    memset(res, 0, sizeof(res));

    int minLength = INT_MAX, dis;
    int i = 0, j = 0, k = 0;
    while(i < extent1 && j < extent2 && k < extent3 && minLength > 0){
        dis = std::abs(S1[i] - S2[j]) + std::abs(S2[j]- S3[k]) + std::abs(S3[k] - S1[i]);
        if(dis < minLength){
            minLength = dis;
            res[0] = S1[i];
            res[1] = S2[j];
            res[2] = S3[k];
        }
        if(xIsMin(S1[i],S2[j],S3[k])) i++;
        else if(xIsMin(S2[j],S3[k],S1[i])) j++;
        else k++;
    }

    for(auto i:res){
        std::cout<<i<<std::endl;
    }

    printf("MinLength is %d", minLength);
}

int main(){
//S1={-1,0,9},S2={-25,-10,10,11},S3={2,9,17,30,41}
    int S1[] = {-1,0,9};
    int S2[] = {-25, -10, 10, 11};
    int S3[] = {2, 9, 17, 30, 41};

    int extent1 = sizeof(S1)/sizeof(*S1);
    int extent2 = sizeof(S2)/sizeof(*S2);
    int extent3 = sizeof(S3)/sizeof(*S3);

    ans(S1, S2, S3, extent1,  extent2, extent3);

    return 0;
}

时间复杂度: O ( e x t e n t 1 + e x t e n t 2 + e x t e n t 3 ) O(extent1_+ extent_2+ extent_3) O(extent1+extent2+extent3)
空间复杂度: O ( 1 ) O(1) O(1)

附录

408历年真题算法题解析

  • 24
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错,可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值