求陣列兩兩之差絕對值最小的值

2021-06-08 17:55:40 字數 3340 閱讀 1294

一 題目描述:

有乙個整數陣列,請求出兩兩之差絕對值最小的值,只要求出最小值即可,不要求求出是哪兩個數。

二 常規思路:

求解此題的尋常思路是什麼?觀察題目我注意到後面強調不要求求出兩個數,那麼最最簡單的o(n^2)的演算法顯然做了很多無用功。嗯,好,既然這個辦法不行想想其他的。對於陣列也就是序列之類的題,有一種很常用的思路那就是

預處理

。這道題目貌似是可以的。

首先,對陣列進行排序,這個可以在o(n*logn)時間之類解決,然後,有了這個預處理,就會想到,絕對值之差最小值肯定只能發生在預處理的陣列之後的相鄰的元素上,這個是很顯然的事實。那麼我們便可以迴圈一遍陣列,記下兩兩之間絕對值的最小值,那麼所求得到值便是解答,總的時間複雜度是o(n*logn)。仔細想想這種方法,很明顯,排序減小了我們所需要搜尋的解空間,從而達到了減小時間複雜度的目的。不過這個解法仍然不能讓人滿意,因為我們還是浪費時間求出了最終的兩個元素,而題目不要求,所以,這肯定不是最優解。

三 轉化的思想

再仔細觀察題目,我們可以猜到,最優解應該是只求出最小值而不求出具體的元素的,那麼該怎麼做呢?我們可能能想到用輔助陣列,但是卻很難想到怎麼做這個輔助。其實這道題我一直在思考如何通過常規的思維去想到這個最優解,不過我當時沒有想出來,而這才是我寫這篇部落格的原因,即促使我了解並對這種思路印象深刻,不過這可能只適用於解這題或者類似能讓我聯想到這種方法的題,這背後更一般的思維(可以叫做轉化,但是還可以更具體些)我還沒有想到,希望想到的同學聯絡我!。

好了,本題要做的輔助陣列是這樣乙個陣列,設它為bn.原來題目中給定的陣列是an,則bn等於:

b1 = a1 - a2;

b2 = a2 - a3;

b3 = a3 - a4;

......

bn-1 = an-1 - an.

注意,bn的長度是n-1,正好比an要小乙個。聰明的同學看到這個輔助陣列,立馬就能猜到原因了,因為這樣做的話,我們能夠把這道看似無從下手求出最優解的問題轉化為求bn的絕對值最小的最長連續子串行和,因為bn的連續子串行和便是an任意兩數之差(注意,由於題目要求的是絕對值最小,所以求出a1-a2等效於得出a2-a1),例如:

a2 - a5 = b2 + b3 + b4 = a2 - a3 + a3 - a4 + a4 - a5 = a2 - a5

實際上,任何ai - aj(ik=j-1)(k)

這樣的話,我們就成功把問題轉化為了連續子串行問題,不過和我們以前做的最大或最小連續子串行還不完全相同,此處是絕對值最小。那麼怎麼樣的值可能是絕對值最小呢?正數最小或者負數最大,也就是說在數軸上離0更近的數其絕對值更小,基於此我們可以得到如下的方法。

和原來求最大連續子串行和一樣,要用數學歸納法思考,我們直接看歸納基礎,

歸納基礎: 假設已知b1..bk的絕對值最小連續的連續子串行和是min(bk)

我們利用這個求解b(k+1),加入b(k+1)後有可能比min(bk)小的只可能是以b(k+1)結尾的絕對值最小的連續子串行和,如果把這個和min(bk)比較就可以知道是否需要更新min(bk)。所以,我們加強這個歸納基礎。

更強的

歸納基礎: 假設已知b1..bk的絕對值最小連續的連續子串行和min(bk),以及以bk結尾的絕對值最小連續子串行和suffix(bk)

有了這個歸納,我們可以去想如何維護這個suffix(bk),目標是使的suffix(b(k+1))仍然是以b(k+1)結尾的最小連續子串行和。如果按照求最小和的思路,那便是只要suffix(bk)是正數便置它為0,因為如果它是正數,那麼在後續求suffix(b(k+1))時就肯定比用0要更大,因為正數會使得整個值變大,而0不會。同樣的道理,我們只要使得求suffix的時候比直接置0更小即可,否則我們可以直接把suffix(b(k+1))置0以獲得更小值。由於我們求的是絕對值最小,直接按最小值的思路是不行的,因為可能某個suffix是暫時求得乙個很小的負數,下次加上某個正數會使得它成為很小的正數,

所以不能以正數負數作定論而要以與0的距離

。所以我們應該採取比較符號的方法,如果當前suffix和下乙個數的符號相反,那麼可以繼續相加以求得下乙個suffix,因為我們可以獲得絕對值更小的suffix;如果是同號,無論正負一定會比把當前suffix置0更糟糕,因為這將使得下次的suffix在數軸上離0更遠。所以我們維護suffix的公式如下: 

suffix(b(k+1)) = suffix(b(k)) + b(k+1), if (suffix(b(k))*b(k+1)) < 0

suffix(b(k+1)) = 0, if (suffix(b(k))*b(k+1)) ) > 0

這樣我們一直歸納下去,便可以求得最終的min(bn),即可求得解。整個的時間複雜度是o(n),空間複雜度是o(n)。

四 程式

程式如下:

1//2

//345

#include

"stdafx.h"6

7#include

<

iostream

>

8#include

<

cmath

>

9using

namespace

std;

1011

intgetminabsolutesubsequence(

intb,

intnlen)

1225

2627

if(i+1

<

nlen)

2832}33

34return

abs(nglobal);35}

3637

intgetminabsolutediff(

inta,

intnlen)

3846

47return

getminabsolutesubsequence(b,nlen-1

);48}49

50int

_tmain(

intargc, _tchar

*argv)51;

53int

nlen=5

;5455cout

<<

getminabsolutediff(a,nlen);

5657

getchar();

58return0;

59}

五 總結

整個思路過程便是這樣,總的來說,這類題目還是很有思考價值的,至少讓我們體會到了各種美,也能深刻領會轉化的意義。

from: 

求陣列兩兩之差絕對值最小的值

一 題目描述 有乙個整數陣列,請求出兩兩之差絕對值最小的值,只要求出最小值即可,不要求求出是哪兩個數。二 常規思路 求解此題的尋常思路是什麼?觀察題目我注意到後面強調不要求求出兩個數,那麼最最簡單的o n 2 的 演算法顯然做了很多無用功。嗯,好,既然這個辦法不行想想其他的。對於陣列也就是序列之類的...

整數陣列中兩兩之差絕對值最小的值

題目1 有乙個整數陣列,請求出兩兩之差絕對值最小的值,記住,只要得出最小值即可,不需要求出是哪兩個數。題目2 請求出最小連續子串行絕對值和,也就是求連續子串行之和的絕對值最小值 針對問題1 方法 1 暴力的方式。遍歷所有的兩個數的差,記錄最小值。演算法的複雜度o n2 方法 2 兩個數要想差的絕對值...

有乙個整數陣列,請求出兩兩之差絕對值最小的值

1.可以快排,然後遍歷一遍排完序後的陣列。時間複雜度為o nlogn n 2.先遍歷一遍陣列a 找出最大值max和最小值min。然後以建立乙個 max min 1 大小的陣列b 再次遍歷原始陣列,b a i min 試圖建立一種對映關係,降低時間複雜度。如下 include include usin...