求一個整數數組元素間最小差值

一、問題描述

       有一個整數數組,請求出兩兩之差絕對值最小的值,記住,只要得出最小值即可,不需要求出是哪兩個數。

       進一步思考:如果需要記錄是哪兩個數呢?

       數組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<<")";


}

 

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