1. 程式人生 > >理解RMQ問題和ST演算法的原理

理解RMQ問題和ST演算法的原理

1.RMQ問題

    RMQ (Range Minimum/Maximum Query):對於長度為n的陣列A,回答若干詢問RMQ(A,i,j)(i,j<=n-1),返回陣列A中下標在i,j範圍內的最小(大)值,也就是說,RMQ問題是指求區間最值的問題。最簡單的方法,就是遍歷陣列直接搜尋,但是這種方式時間複雜度是O(n)。對於陣列長度較大,效能要求高的場景不適用。

2.ST(Sparse Table)演算法

ST演算法是一種更加高效的演算法,以O(nlogn)的預處理代價,換取O(1)的查詢時效能。現在我們來看下ST演算法的思路和求解過程。假設有一個長度n=10的陣列a,各個陣列元素a[0],a[1]……a[9]的值分別是3 ,2, 4, 5 ,6, 8 ,1,2, 9, 7。
我們以求最大值為例,令0 <= i <= j <= n-1,那麼RMQ(a,i,j)就是:找出a[i],a[i+1]....a[j]這些元素中的最大值。令 f[i,j]代表從第i個數起連續2^j個數中的最大值 顯然f[i,0]的值是確定的,就是第i個數自己。即f[i,0] = a[i],這就是動態規劃DP的初始條件值 現在我們來看下動態規劃的狀態轉移方程,有了初始值和動態轉移方程,就能夠用動態規劃演算法解決問題。 為了求f[i,j],我們把f[i,j]平均分成兩段(因為f[i,j]一定是偶數個數字),從i到i+2^(j-1)-1為一段,i+2^(j-1)到i+2^j-1為一段(長度都為2^(j-1))。顯然f[i , j] = max(f[i ,  j-1],f[ i + 2^(j-1),  j-1
])
目前為止,已經有了DP的初始化條件和狀態轉移方程。接下來我們來看如何利用f[i,j]來RMQ(a, i, j)。 k=[log2(j-i+1)],則有:RMQ(a, i, j) = max{f[i,k], f[j-2^k+1,k]}
舉例說明,如果要求區間[2,8]的最大值,總共2到8是7個元素,所以k=2,那麼就要把它分成[2,5]和[5,8]兩個區間,因為這兩個區間的最大值我們可以直接由f[2,2]和f[5,2]得到。
現在我們看下k的值是如何得出的。假設拆分成的2個子區間,每個子區間都有2^(k-1)個元素。則2個子區間分別為: [i, 2^(k-1) + i -1]和[j - 2^(k-1) + 1,j]。顯然必須要滿足2個子區間能夠完全覆蓋[i,j],即(2^(k-1) + i -1) + 1 >= (j - 2^(k-1) +1
進而可以推匯出 2^k >= (j - i + 1)。這樣的話,我們取滿足條件的K最小值就可以了。為什麼要取最小值呢?是為了保證2個子區間長度儘可能的短。