1. 程式人生 > >11 Container With Most Water的數學證明 | LeetCode

11 Container With Most Water的數學證明 | LeetCode

Given n non-negative integers a1, a2, …, an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.

Note: You may not slant the container and n is at least 2.

Example: Input: [1,8,6,2,5,4,8,3,7] Output: 49

網上給出的最優演算法都比較類似,其基本想法是:將挑選的兩條邊分別從兩端a0,ana_0, a_n開始向中間移動,每一次只能移動兩條邊中的一條。每次移動的標準是將較小的那條邊往中間移動一格。如果移動後的面積有所增長,則將面積最大值更新。當兩條邊相遇時,則停止。

網上幾乎都只有這個演算法的描述,而沒有提供一個嚴格的數學證明。和好友Meiyf討論後,整理出這個演算法的數學證明。

考慮分佈在左右兩邊的移動指標a

l,ara_l, a_r,它們分別從兩端a0,ana_0, a_n開始,通過ala_l右移、ara_r左移的方式,來搜尋最優解。

假設最優解為ai,aja_i, a_j,則我們有:0i<jn0 \leq i < j \leq n。根據演算法的移動方式,總是可以通過“ala_la0a_0右移、ara_rana_n左移”若干步的方式,到達ai,aja_i, a_j

由於演算法每一次只能移動一步(即ala_l右移一步或ara_r左移一步),所以兩種情況:

  • a
    la_l
    先到達aia_i
  • ara_r先到達aja_j

必然有一種先發生。不妨假設ala_l先到達aia_i(那麼此時,ara_r也就還未通過左移到達aja_j,它還在aja_j的右側)。那麼,我們只需證明:

在現有的演算法下,後續的更新步驟__都只能是__:ara_r不斷左移、直到到達aja_j

我們可以通過反證法來證明上述結論。

令函式h(at)h(a_t)表示點ata_t對應的線段長度,令w(as,at)w(a_s, a_t)表示點asa_sata_t構成的線段長度。

若假設不成立,則存在某一步:在ara_r還未通過左移到達aja_j時,停留在aia_iala_l需要右移一步。

下面我們來證明不可能出現上面這種情況。

若上述發生,則我們有以下結論:

  1. l=i<j<rl = i < j < r
  2. h(ai)=h(al)<h(ar)h(a_i) = h(a_l) < h(a_r)。因為根據演算法,只有長度更小的那一條邊才能向中間移動。所以,只有當h(al)h(a_l)小於h(ar)h(a_r)時,才可能出現ala_l右移。

由此,我們可以得到由ai,ara_i, a_r兩條邊形成的面積為:S=h(ai)w(ai,ar).S^* = h(a_i) * w(a_i, a_r).

這裡的高度之所以取為h(ai)h(a_i),是因為上面第2條已經說明了h(ai)h(a_i)h(ar)h(a_r)小。

而此時,因為第1條已經說明j<rj < r,所以w(ai,ar)>w(ai,aj)w(a_i, a_r) > w(a_i, a_j)。所以我們有:

S=h(ai)w(ai,ar)>h(ai)w(ai,aj)min{h(ai),h(aj)}w(ai,aj)=SmaxS^* = h(a_i) * w(a_i, a_r) > h(a_i) * w(a_i, a_j) \geq \min{\{h(a_i), h(a_j)\}} * w(a_i, a_j) = S_{max}

矛盾。所以假設命題不成立,進而當ala_l到達aia_i後,後續的所有更新步驟都只能是ara_r不斷左移、直到到達aja_j

所以,在這樣的演算法之下,一定能夠到找到面積的最優解SmaxS_{max}