以我個人的看法,與其說rmq是演算法,還不如說是一類問題,即區間(range)最大/小值(minimum/maximum)查詢(query)
有三種辦法可以解決這類問題
第一種是暴力查詢
for
(int i=n1,i<=n2;i++
)
如果查詢次數是0第三種st方法,可以在o(nlogn)的預處理之後做到o(1)的查詢速度
原理大概是二分吧
分成兩部分:預處理和查詢
難點是迴圈的控制(賊難受,思考了很長時間才稍微理解)
先說預處理:
以最大值為例:
假設有陣列arr,陣列長度len
那麼我們需要來乙個二維陣列dp[i][j];
i 是1<=i<=len的規模
j 是log2(len)的規模
為啥?因為dp[i][j]的含義是從下標為i的字元開始,往後2j個字元的最大值
也就是dp[i][j] = for(arr[i]到arr[i+2j-1])的最大值
那麼dp[i][0] 就是從arr[i]開始20=1個字元的最大值,這裡需要說一下,我們不用0下標,也就是說dp[i][0]就是arr[i]
o(nlogn)
通過乙個雙重迴圈
for
(int j=1;
(1<< j )
<=len;j++
)//很奇怪是吧?為什麼和以往把i放在外面的思路不一樣呢?
for(
int i=
1;i +(1
<< j)-1
<=len;i++
) dp[i]
[j]=
max(dp[i]
[j-1
],dp[i +(1
<< j-1)
][j-1]
);
把陣列原模原樣的弄到dp中是這個樣子的
之後我們把j放在外面,把i放在裡面做迴圈,為的是讓陣列一列一列的dp而不是一行一行的dp,如果把i放在外面,情況就是這樣的:
dp[1][1] = max(dp[1][0],dp[1+1][0]);沒問題,等於1
dp[1][2] = max(dp[1][1],dp[1+2][1]);dp[1][1]是有了,但是dp[3][1]不是還沒加工嗎?
dp思想:也就是說,每段dp元素的值是之前已經處理過的兩個元素之間的關係得出來的
然後我們先抽象的理解下這段原理
dp[i][k],也就是說把從i開始到i+2k-1個元素的最值找到並存到dp[i][k]中去,
那麼我們可以吧這段分兩份一起找
乙份是從 i 到i +2k-1-1
這不就是dp[i][k-1]嗎
乙份是從i + 2k-1到 i + 2k-1
兩份長度都是2k-1
長度一樣, j 值一樣, i 加上 2k-1
就是dp[i+(1 << j-1)][j-1]的來歷
正好湊出2k個元素
舉例 dp[2][3] = max(dp[2][2] , dp[2+22][2])
黃色代表dp[2][2]的整體,綠色代表dp[2 + 22][2]的整體,dp[2][3]最後成綠色代表綠色找出來的值更大
int
find
(int n1,
int n2)
k的作用是把區間的長度對2取對數的向下取整
找到區間n1的 j 標
這樣就不把從n1開始到下標n1+2n-1的值全都檢索一遍了嗎
那麼問題來了:
既然是向下取整,2k一定是小於等於n2-n1+1的,缺少的一部分怎麼辦?
我們可以直接從n2往前找
不會把,不是說 j 標是往後2j個嗎?
對,所以我們直接找n2前面2k的值就可以了
也就是**dp[n2-(1<
來張感受一下
poj3264
uva 11235(我進不去uva**。。。不會翻牆)
演算法討論 RMQ 學習筆記
模板及講解 運用st表實現區間詢問區間最大 最小,初始化時間複雜度o nlog n 查詢o 1 模板題 poj 3264 include include include include define ms i,j memset i,j,sizeof i using namespace std con...
RMQ(範圍最值問題)演算法學習
rmq演算法適合求解對乙個陣列多次查詢給定範圍內的最值。預處理操作 令d i,j 表示從i開始,長度為2 j的一段元素的最值,可以用遞推公式寫出d i,j min 原理如圖所示 複雜度 因為2 j n,所以d陣列的元素不會超過nlogn個,計算每個d需要o 1 所以總的時間複雜度是o nlogn 查...
演算法 學習筆記
1.輸入輸出演算法至少有乙個或多個輸出 2.有窮性 3.確定性 4.可行性 1.正確性a.演算法程式沒有語法錯誤 b.演算法程式對於合法的輸入資料能夠產生滿足要求的輸出結果 c.演算法程式對於非法的輸入資料能夠得出滿足規格說明的結果 d.演算法對於精心選擇的,甚至刁難的測試資料都有滿足要求的輸出結果...