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

2021-06-18 08:12:17 字數 3223 閱讀 1093

一 題目描述:

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

二 常規思路:

求解此題的尋常思路是什麼?觀察題目我注意到後面強調不要求求出兩個數,那麼最最簡單的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)。

四 程式

程式如下:

[cpp]view plain

copy

#include"stdafx.h" 

#include

#include

usingnamespacestd;   

intgetminabsolutesubsequence(intb,intnlen)  

}  returnabs(nglobal);  

}  int

getminabsolutediff(inta,

intnlen)  

returngetminabsolutesubsequence(b,nlen-1);  

}  int_tmain(intargc, _tchar*argv)  

;  int

nlen=5;  

coutreturn0;  

}  

五 總結

整個思路過程便是這樣,總的來說,這類題目還是很有思考價值的,至少讓我們體會

到了各種美,也能深刻領會轉化的意義。

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

一 題目描述 有乙個整數陣列,請求出兩兩之差絕對值最小的值,只要求出最小值即可,不要求求出是哪兩個數。二 常規思路 求解此題的尋常思路是什麼?觀察題目我注意到後面強調不要求求出兩個數,那麼最最簡單的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...