1. 程式人生 > >RMQ問題第一彈

RMQ問題第一彈

表達 能夠 aic 如何 組合 展示 要求 二維 sae

技術分享


今天,我給大家分享一下我在學習 RMQ 問題過程中對該問題的理解。

RMQ (Range Minimum/Maximum Query ):中文名為“區間最值查詢”。RMQ 問題指的是給定一段區間,針對給定區間進行若幹次查詢,每次給出不同的待查詢子區間範圍,要求返回子區間內的最大值或者最小值。

一般此類問題會給出區間內總元素個數 n 、待查詢的次數 q ,以及每次查詢的始末位置。

根據常規的思路,要找出一段區間中的最大值或最小值,我們會采取遍歷區間的做法,該方法的核心代碼在此不作展示。分析可知,n 個數據的規模,進行 q 次查詢,時間復雜度為 o(q*n ),當問題的規模逐漸增大或者查詢的次數逐漸增多的時候,我們無法在有限的時間內完成任務。因此,尋找更方便更快捷的辦法成為我們的目標。在學習算法的道路上,我們都知道,第一直覺想出來的解決思路往往是最直接也是最低效的,於是理所當然的,我們需要對原來的思路進行改進,甚至摒棄原來低效的方法另辟蹊徑。常規的思路時間主要耗費在對最值的查詢和求解工作上,我們可以想辦法將查詢時間縮短,有人提出將可能查詢的區間列出來,針對每個區間找出其中的最值存儲在數組裏,每次查詢最值數組即可,這個思路需要存儲的量有三個,起始點、終止點、區間最值,可以考慮模仿動態規劃的理念,對二維數組的兩個下標和存儲的值賦予特殊含義,即用二維數組的第一坐標表示起始點、第二坐標表示終止點,那麽值就可以表示區間最值。這樣一來,查詢的時間縮短為 o(1),但是問題在於,該 n* n 的二維數組賦值的時候,如果采用遍歷對應區間的方法求最值,整個二維數組賦值過程時間復雜度為 o(n^3),這就意味著,雖然做了多余的工作,也做了合理的設想,但是並未達到優化問題的目的。這是不是意味著當前的思路不可行呢?我們需要先考慮該二維數組賦值過程能不能優化,如果不能,那這個思路就可以宣布失敗了。

天無絕人之路,機會總是偏愛大膽實踐的人。我們可以在此作出大膽預測,如果采用以上對二維數組的定義:第一坐標表示起始點,第二坐標表示終止點,值表示最值,即使求解最值的方法時間復雜度是 o(1),那求解該二維數組的整個過程時間復雜度也在 o(n^2),我們知道並沒有 o(1)求解亂序區間最值的方法,因此,可以得出結論,以上對二維數組的定義無法達到優化的目的。

這就意味著問題不僅出現在求解區間最值的方法上,同時基本的二維數組定義也是不合理的。不合理之處在於規模過大,我們需要想辦法縮小二維數組的規模。表示某一區間和其最值除了首末端點和最值三個參數這種方法,還可以用區間起始點、區間長度、區間最值三個參數。區間長度範圍是 1 ~ n ,換個思路想一下,表示區間長度時候定義可以是多樣的。

由此衍生出第二種方法-- ST 方法。

技術分享

ST(Sparse Table)方法,sparse 中文譯為:稀疏的,稀少的,零星的;table 中文譯為:桌子,表,目錄,手術臺,工作臺,遊戲臺;Sparse Table 具體中文名到底如何翻譯,沒有一個固定說法,我們暫且稱之為 ST方法,該方法的本質是用動態規劃方法求出用於查詢的最值數組,以待查詢子區間的起始位置和區間長度標記一個狀態,以該子區間內的最大值或最小值作為狀態值。

以求最大值為例: dp[ i ][ j ] = max ,其中,i 表示待查詢子區間起始位置 ;j 表示待查詢子區間的長度為 2 ^ j , max 表示在該子區間中最大值為 max 。 分析可知:1 <= i <= n , 0 <= j <= log n (以 2 為底), 此時,二維數組的規模為 n *log n (以 2 為底) 。動態規劃的表達式有了,現在我們來研究狀態轉換方程,由 dp 數組的定義可以看出來,dp[ i ][ j ] 表示的區間長度 2 ^ j 一定是偶數,因此,區間可以等分為兩個長度為 2 ^( j - 1 ) 的子區間,依照分治的思想,求該區間的最值,可以通過選擇兩個子區間最值中的最值來實現。此時,狀態轉換方程為:

dp[ i ] [ j ] = max ( dp[ i ][ j - 1 ] , dp[ i + 2^( j - 1 ) - 1][ j - 1 ] )

求最值數組具體的核心代碼實現過程如下:

技術分享

註意,第 13 行的註釋“ j 必須為外層循環控制量”,原因在於求解過程中,先求出以各元素為初始元素區間長度為 1 的最值,再求出以各元素為初始元素區間長度為 2 的最值,依次求解。因此 i 為內層循環控制量, j 為外層循環控制量,而不能以 i 為外層循環控制量,因為此時假設 求 dp[ i ] [ j ] ,如果 i 為外層循環控制量,dp[i][j] = max( dp[i][j-1] , dp[i + 2 ^(j-1) - 1][j-1]) ,其中 dp[ i ][ j - 1] 已知 ,但是 dp[i + 2 ^(j-1) - 1][j-1] 未知的,準確說, 第一坐標值 大於 i 的值都是未知的。

查詢的時候,已知的信息是始末元素下標 start 和 end ,我們的 dp 數組中存儲的是長度為 2 的冪的區間最值,對於長度非 2 的冪的區間,我們需要找到能夠覆蓋這個區間的兩個區間,選取兩者的最值即可。

如下,求下標 1 ~12 的元素中的最值,log 12 (以 2 為底)= 3 ,因此選取 F(1,3)和 F(5,3)兩個區間,組合起來可以覆蓋待求區間的所有數據。

技術分享

查詢部分核心代碼如下:

技術分享

今天的分享就到這裏,其他相關的方法且看下篇文章。


技術分享感謝大家對我的支持,沒關註的朋友可以掃下方二維碼關註我呦。

技術分享

RMQ問題第一彈