求一个整数数组元素间最小差值

一、问题描述

       有一个整数数组,请求出两两之差绝对值最小的值,记住,只要得出最小值即可,不需要求出是哪两个数。

       进一步思考:如果需要记录是哪两个数呢?

       数组A[n]

二、解题思路

1、暴力穷举法:n个数两两做差,取最小值。O\left ( n^{2}\right )

2、先用快排将数组A排序,再两两做差,取最小值。O\left (nlogn\right )

3、利用辅助数组B[n-1]

     B_{0}=A_{0}-A_{1}

     B_{1}=A_{1}-A_{2}

    ……

    B_{n-1}=A_{n-1}-A_{n}

     所以任意A中任意两个数之差,可以表示为B数组中子序列相加。例如A_{3}-A_{5}=B_{4}+B_{3}。时间复杂度O\left (n ^{2} \right )

三、代码实现。

1、穷举法 略 (若要记录两个数的索引值,只需要在遍历的时候记录取最小值时的i,j即可)

2、先用快排,再两两做差.。(这个方法要记录两个数的索引值比较麻烦。)

#include<iostream>
#include<algorithm>
#include<limits.h>
using namespace std;

int main(){
    int arr[]={1,5,3};
    int n=sizeof(arr)/sizeof(arr[0]);
    sort(arr,arr+3);
    for(int i=0;i<n;i++){
        cout<<arr[i];
    }
    int min=INT_MAX;
    for(int i=1;i<n;i++)
    {
        if(arr[i]-arr[i-1]<min)
            min=arr[i]-arr[i-1];
    }
    cout<<endl<<"×îС²î"<<min;
}

输入:[1,5,3]

3、辅助数组法

先构造辅助数组b[n-1] 时间复杂度O\left ( n \right )

在使用动态规划思想求b[n-1]中最小绝对值子序列

创建dp[i][j]表示从b_{i}b_{j}所有元素相加的和。

初始化:dp[i][i]=b[i]

递推公式:dp[i][j]=dp[i][j-1]+b[j]

代码如下:

#include<iostream>
#include<algorithm>
#include<limits.h>
#include<algorithm>
using namespace std;

int dp[10000+10][10000+10];

int main(){
    int arr[]={1,7,6,12,8,0};
    int n=sizeof(arr)/sizeof(arr[0]);
    int b[n-1];
    for(int i=0;i<n-1;i++)
    {
        b[i]=arr[i]-arr[i+1];
    }
    //初始化dp[i][i]=b[i],
    int min=INT_MAX;
    for(int i=0;i<n-1;i++){
        dp[i][i]=b[i];
    }

    int pos1=0,pos2=1;//记录绝对值最小的两个数的索引
    //dp[0][1]=b[0]+b[1];
    //dp[i][j] 从bi到bj所有元素相加的和
    //递推公式 dp[i][j]=dp[i][j-1]+b[j]
    for(int i=0;i<n-1;i++)
    {
        for(int j=i;j<n-1;j++){
            dp[i][j]=dp[i][j-1]+b[j];
            if(abs(dp[i][j])<min)
            {
                min=dp[i][j];
                pos1=i;
                pos2=j+1;
            }
        }
    }
    for(int i=0;i<n-1;i++)
    {
        for(int j=i;j<n-1;j++)
            cout<<"dp("<<i<<","<<j<<")"<<"="<<dp[i][j]<<" ";
        cout<<endl;
    }
    cout<<"整数数组中两两之差绝对值最小"<<min<<" 索引值"<<"("<<pos1<<","<<pos2<<")";


}

这里我用pos1,pos2变量记录了最相近两数的索引值

输入:[1,7,6,12,8,0]

 

四、类似题。(我也不确定类不类似)

输入数组A[n]。输出n-1行,第i行输出,A[i]之前的数中,与A[i]最接近的数的索引值和两者的差的绝对值。

只写了暴力法解决的:

#include<iostream>
#include<algorithm>
#include<limits.h>
#include<algorithm>
using namespace std;

int dp[10000+10][10000+10];

int main(){
    int arr[]={1,7,6,12,8,0};
    int n=sizeof(arr)/sizeof(arr[0]);
    int b[n-1];
    for(int i=0;i<n-1;i++)
    {
        b[i]=arr[i]-arr[i+1];
    }
    //初始化dp[i][i]=b[i],
    int min=INT_MAX;
    for(int i=0;i<n-1;i++){
        dp[i][i]=b[i];
    }

    int pos1=0,pos2=1;//记录绝对值最小的两个数的索引
    //dp[0][1]=b[0]+b[1];
    //dp[i][j] 从bi到bj所有元素相加的和
    //递推公式 dp[i][j]=dp[i][j-1]+b[j]
    for(int i=1;i<n-1;i++)
    {
        for(int j=i;j<n-1;j++){
            dp[i][j]=dp[i][j-1]+b[j];
            if(abs(dp[i][j])<min)
            {
                min=dp[i][j];
                pos1=i;
                pos2=j+1;
            }
        }
    }
    for(int i=0;i<n-1;i++)
    {
        for(int j=i;j<n-1;j++)
            cout<<"dp("<<i<<","<<j<<")"<<"="<<dp[i][j]<<" ";
        cout<<endl;
    }
    cout<<"整数数组中两两之差绝对值最小"<<min<<" 索引值"<<"("<<pos1<<","<<pos2<<")";


}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章