日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RMQ算法讲解

發(fā)布時間:2023/12/4 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RMQ算法讲解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。 本文鏈接:https://blog.csdn.net/qq_41311604/article/details/79900893 </div><!--一個博主專欄付費(fèi)入口--><!--一個博主專欄付費(fèi)入口結(jié)束--><link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css"><link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css"><div class="htmledit_views" id="content_views"><p>現(xiàn)在給你一個問題:給你一個數(shù)組 ,其中有N個數(shù)字,現(xiàn)在給你一次詢問,給你區(qū)間[l ,r],問你在這個區(qū)間內(nèi)的最大值為多少?</p>

哇!這題簡單啊,一個for循環(huán),遍歷數(shù)組記錄最大值輸出即可啊。

?

那好,現(xiàn)在我告訴你假設(shè)N為50000,給你Q次詢問((1 ≤ Q ≤ 200,000)),如果這種情況,我們還每次都進(jìn)行暴力遍歷求解的話,那么無論你提交幾萬次都會得到如下結(jié)果:

?

是的,這種暴力遍歷求解雖然思維簡單,代碼簡短,但是很慢啊。

?

那該怎么做呢?以前我也不會啊,自從學(xué)了RMQ,誒,真好用,我們?nèi)叶加盟?#xff01;

?

RMQ(Range Minimum/Maximum Query),即區(qū)間最值查詢。RMQ算法一般用較長時間做預(yù)處理,時間復(fù)雜度為O(nlogn),然后可以在O(1)的時間內(nèi)處理每次查詢。

?

下面我們從一個實際問題來解釋RMQ

我們假設(shè)數(shù)組arr為:1,2,6,8,4,3,7

我們設(shè)二維數(shù)組dp[i][j]表示從第i位開始連續(xù) 個數(shù)中的最小值。例如dp[2][1]就表示從第二位數(shù)開始連續(xù)兩個數(shù)的最小值(也就是從第二位數(shù)到第三位數(shù)的最小值),即2,6中的最小值,所以dp[2][1] = 2;

?

其實我們求 dp[i][j] 的時候可以把它分成兩部分,第一部分是從 到 ,第二部分從到 ,為什么可以這么分呢?其實我們都知道二進(jìn)制數(shù)前一個數(shù)是后一個的兩倍,那么可以把 到 這個區(qū)間通過分成相等的兩部分,?那么轉(zhuǎn)移方程很容易就寫出來了。(dp[i][0]就表示第i個數(shù)字本身)

?

dp[i][j] = min(dp [i][j - 1], dp [i + (1 << j - 1)][j - 1])

由此給出下列代碼:

  • void rmq_init()
  • {
  • for(int i=1;i<=N;i++)
  • dp[i][0]=arr[i];//初始化
  • for(int j=1;(1<<j)<=N;j++)
  • for(int i=1;i+(1<<j)-1<=N;i++)
  • dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
  • }
  • 這里需要注意一個循環(huán)變量的順序,我們看到外層循環(huán)變量為j,內(nèi)層循環(huán)變量為i,這是為什么呢?可以互換一下位置嗎?

    ?

    答案當(dāng)然是不可以,我們要理解這個狀態(tài)轉(zhuǎn)移方程的意義,這個狀態(tài)方程的含義是:先更新每兩個元素中的最小值,然后通過每兩個元素的最小值獲得每4個元素中的最小值,依次類推更新所有長度的最小值。

    ?

    而如果是i在外,j在內(nèi)的話,我們更新的順序就變成了從1開始的前1個元素,前2個元素,前4個元素,前8個元素。。。

    當(dāng)j等于3的時候dp[1][3] = min(min(ans[0],ans[1],ans[2],ans[3]),min(ans[4],ans[5],ans[6],ans[7])))的值,

    但是我們根本沒有計算min(ans[0],ans[1],ans[2],ans[3])和min(ans[4],ans[5],ans[6],ans[7]),所以這樣的方法肯定是錯誤的。

    為了避免這樣的錯誤,一定要好好理解這個狀態(tài)轉(zhuǎn)移方程所代表的含義。

    ?

    接下來我們來講解RMQ的查詢部分,假設(shè)我們需要查詢區(qū)間[l ,r]中的最小值,令k = , 則區(qū)間[l, r]的最小值RMQ[l,r] = min(dp[l][k], dp[r - (1 << k) + 1][k]);

    ?

    但是為什么這樣就可以保證是區(qū)間最小值了呢?

    ?

    dp[l][k]維護(hù)的是區(qū)間 [l, l + 2^k - 1] , dp[r - (1 << k) + 1][k]維護(hù)的是區(qū)間 [r - 2^k + 1, r] 。

    那么只要我們保證? ≤ 就能保證RMQ[l,r] = min(dp[l][k], dp[r - (1 << k) + 1][k]);


    ?

    接下來我們用分析法來證明這個不等式:

    我們假設(shè) ? ≤ 這個等式成立

    即有 r - l + 2 ≤ 也就是 r - l + 2 ≤

    又因為 k = ;

    那么 r - l + 2 ≤ 2 * (r - l +1)

    則 r - l + 2 ≤ 2*(r - l) + 2

    即 r - l ≤ 2*(r-l)

    所以 r - l ≥ 0,即假設(shè)成立

    我們舉個例子, l = 4,r = 6;

    假設(shè)數(shù)組arr為:1,2,6,8,4,3,7

    此時 k = = = 1

    則區(qū)間[4,6]的最小值 = min(dp[4][1],dp[5][1])

    dp[4][1] = 4,dp[5][1] = 3,所以區(qū)間[4,6]的最小值 = min(dp[4][1],dp[5][1]) = 3

    我們很容易看出來答案是正確的。

    由此給出查詢部分代碼:

  • int rmq(int l,int r)
  • {
  • int k=log2(r-l+1);
  • return min(dp[l][k],dp[r-(1<<k)+1][k]);
  • }
  • ?
  • 好了,至此RMQ全部介紹完畢。

    總結(jié)

    以上是生活随笔為你收集整理的RMQ算法讲解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。