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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RMQ(Range Minimum Query)

發布時間:2024/4/15 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RMQ(Range Minimum Query) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

問題

????? RMQ問題是求給定區間中的最值問題。對于長度為n的數列A,回答若干查詢RMQ(A, i, j)。返回數組A中下標在[i,j]里的最小值的下標。比如數列 5,8,1,3,6,4,9,5,7 ? ? ?那么RMQ(2,4) = 3, RMQ(6,9) = 6.

解決方法

主要方法及復雜度(處理復雜度和查詢復雜度)如下:?

  • 樸素(即搜索) O(n)-O(n)?

  • ST(實質是動態規劃) O(nlogn)-O(1)?

  • 線段樹(segment tree) O(n)-O(qlogn)


  • 樸素

    ????即是直接搜索,對被查詢的空間進行直接遍歷,時間復雜度為O(n)

    ST

    ??? Sparse Table,它是一種動態規劃的方法。?
    ??? 以最小值為例。a為所尋找的數組.?用一個二維數組f(i,j)記錄區間[i,i+2^j-1](持續2^j個)區間中的最小值。其中f[i,0] = a[i];?所以,對于任意的一組(i,j),f(i,j) = min{f(i,j-1),f(i+2^(j-1),j-1)}來使用動態規劃計算出來。?這個算法的高明之處不是在于這個動態規劃的建立,而是它的查詢:它的查詢效率是O(1).?
    ???? 假設我們要求區間[m,n]中a的最小值,找到一個數k使得2^k<n-m+1.?這樣,可以把這個區間分成兩個部分:[m,m+2^k-1]和[n-2^k+1,n].我們發現,這兩個區間是已經初始化好的.?
    前面的區間是f(m,k),后面的區間是f(n-2^k+1,k).?
    ???? 這樣,只要看這兩個區間的最小值,就可以知道整個區間的最小值!?


    偽代碼:

    //初始化INIT_RMQ//max[i][j]中存的是從i開始的2^j個數據中的最大值,最小值類似,num中存有數組的值for?i?:?1?to?nmax[i][0]?=?num[i]for?j?:?1?to?log(n)/log(2)for?i?:?1?to?(n+1-2^i)max[i][j]?=?MAX(max[i][j-1],?max[i+2^(j-1)][j-1])//查詢RMQ(i,?j)k?=?log(j-i+1)?/?log(2)return?MAX(max[i][k],?max[j-2^k+1][k])

    C++模板:

    /***?@brief?sparse?algorithm*?@author?xiyan*?@date?2014/6/17*?@last?edit**/ #include?<cstdlib> #include?<iostream> #include?<cmath> typedef?unsigned?int?size_t; typedef?int?ssize_t; namespace?rmq{ using?namespace?std; template<typename?T> class?sparseTable{ public: ssize_t?createSt(const?T?*arrayPtr,?const?ssize_t?arraySize);????????? /*build?st?by?input*/ const?T?*searchSt(const?ssize_t?startPos,?const?ssize_t?endPos);????? /*lookup?the?min?val?from??startPos?to?endPos*/ virtual?~sparseTable(void);?????????????????????????????????????????????? /*destory?st?when?class?destory*/ virtual?void?debug(void); private:ssize_t?allocSt(const?ssize_t?arraySize);???????????????/*alloc?space?for?st*/ssize_t?initSt?(const?T?*arrayPtr);?????????????????????/*init?St*/ssize_t?stLog(ssize_t?size)?const;??????????????????????/*make?lg(size)*/???T?*?getItem(const?ssize_t?base,?const?ssize_t?logTots);?/*get?item?from?sparse?table*/????????????????????????void?destorySt(void);ssize_t?*getMaxLogTots(void){???????????????????????????return?&tot_row;}???????????????ssize_t?*getMaxBase(void){return?&tot_col;}T?*dpSt;???????????????????????????????????????????????????/*sparse?table*/ssize_t?tot_row;???????????????????????????????????????????/*sparee?table?tot?row*/ssize_t?tot_col;???????????????????????????????????????????/*sparse?table?tot?col?*/ }; /***?@brief?deinit?api?for?st*?@note?call?destorySt?to?do?clean?task*/ template<typename?T> void?sparseTable<T>::debug(void){cout?<<?"tot?nums(lg):"<<?*getMaxLogTots()?<<?endl;cout?<<?"tot?base????:"<<?*getMaxBase()?<<?endl;if(dpSt){for(ssize_t?tot?=?0;?tot?<?*getMaxLogTots();?tot++)for(ssize_t?base?=?0;?base?<?*getMaxBase();?base++){cout?<<?"Logtot?"?<<?tot;cout?<<?",";cout?<<?"base?"?<<?base;cout?<<?"|?->";cout?<<?*getItem(base,?tot)?<<?endl;}} } /***?@brief?deinit?api?for?st*?@note?call?destorySt?to?do?clean?task*/ template<typename?T> void?sparseTable<T>::destorySt(void){delete?dpSt; } /***?@brief?play?as?a?cleaner?when?destory?st**/ template<typename?T> sparseTable<T>::~sparseTable(void){destorySt(); } /***?@brief?2^n?<=?size,?return?n;?*?@return?n?success,?-1?fail**/ template<typename?T> ssize_t?sparseTable<T>::stLog(const?ssize_t?size)?const?{ssize_t?ans??=?0;if(size?<=?0){return?-1;}while(?(1?<<?ans)?<=?size){++ans;}ans--;return?ans; } /***?@brief?create?sparse?Table*?@param[in]?arrayPtr?base?data?store?in?array?for?building?sparse?table*?@param[in]?data?tots*?@return?0?success,?-1?fail*/ template<typename?T> ssize_t?sparseTable<T>::allocSt(const?ssize_t?arraySize){ssize_t?*maxBase????=?getMaxBase();ssize_t?*maxLogTots?=?getMaxLogTots();?*maxBase?????=?arraySize;*maxLogTots??=?stLog(arraySize);if(?*maxLogTots?<?0){return?-1;}*maxLogTots?+=?1;ssize_t?totSize?=?(*maxBase)?*?(*maxLogTots);dpSt?=?new?T[totSize];if(NULL?==?dpSt){return?-1;}return?0; }/***?@brief?get?Item?from?table?*?@note?*??????1.?row?act?as?totnums?cnt*??????2.?col?act?as?idx?for?base?num*??????3.?col?>=?row?for?Table?*/????? template<typename?T> T?*sparseTable<T>::getItem(const?ssize_t?base,?const?ssize_t?logTots){if(?!dpSt?||?base?<?0?||?logTots?<?0?||?base?>=?*getMaxBase()?||?logTots?>=?*getMaxLogTots()){return?NULL;}return?(&dpSt[logTots?*?(*getMaxBase())?+?base]); } /***?@brief?init?sparse?Table?by?input?*?@param[in]?arrayPtr?ptr?to?the?imput?array*/ template<typename?T> ssize_t?sparseTable<T>::initSt(const?T?*arrayPtr){for(ssize_t?base?=?0;?base?<?*getMaxBase();?base++){????????????T??*?itemPtr?=?getItem(base,?0);if(NULL?==?itemPtr){return?-1;}*itemPtr?=?arrayPtr[base];} #if?0cout?<<?"init?phase0?success"?<<?endl; #endiffor(ssize_t?logTots?=?1;?logTots?<?*getMaxLogTots();?logTots++){for(ssize_t?base?=?0;?((base?+?(1?<<??logTots)?)?<=?(*getMaxBase()));?base++){??T?*lItem?=?getItem(base,?logTots?-?1);?T?*rItem?=?getItem(base?+?(1?<<?(logTots?-?1)),?logTots?-?1);T?*cItem?=?getItem(base,?logTots);if(NULL?==?lItem?||?NULL?==?rItem||?NULL?==?cItem){return?-1;}*cItem?=?(*lItem?<?*rItem???*lItem?:?*rItem);}} #if?0cout?<<?"init?phase1?success"?<<?endl; #endifreturn?0; } /***?@brief?create?and?init?sparse?table*?@param[in]?arrayPtr?ptr?to?the?input?array*?@param[in]?arrSize??tot?nums?of?input**/ template<typename?T> ssize_t?sparseTable<T>::createSt(const?T?*arrayPtr,?const?ssize_t?arraySize){???????????? /*build?st?by?input*/if(allocSt(arraySize)??<?0){cout?<<?"alloc?sparse?table?fail"?<<?endl;return?-1;}if(initSt(arrayPtr)?<?0){destorySt();cout?<<?"init?sparse?table?fail"?<<?endl;return?-1;}return?0; }/***?@brief?search?the?min?num*?@param[in]?arrayPtr?ptr?to?the?input?array*?@param[in]?arrSize??tot?nums?of?input**/ template<typename?T> const?T?*?sparseTable<T>::searchSt(const?ssize_t?startPos,?ssize_t?endPos){???ssize_t?logPos;if(startPos?<?0?||?endPos?<?0||?startPos?>=?*getMaxBase()?||?endPos?>=?*getMaxBase()||?startPos?>?endPos){return?NULL;}logPos?=?stLog(endPos?-?startPos?+??1);if(logPos?<?0){return?NULL;}T?*lItem?=?getItem(startPos,?logPos);?T?*rItem?=?getItem(endPos?-?(1?<<?logPos)?+?1,?logPos);if(NULL?==?lItem?||?NULL?==?rItem){return?NULL;}return?(*lItem?<?*rItem???lItem?:?rItem); } }//?end?of?sparse?table?

    線段樹

    線段樹能在對數時間內在數組區間上進行更新與查詢。?定義線段樹在區間[i, j] 上如下:?
    第一個節點維護著區間 [i, j] 的信息。?
    if i<j , 那么左孩子維護著區間[i, (i+j)/2] 的信息,右孩子維護著區間[(i+j)/2+1, j] 的信息。?
    可知 N? 個元素的線段樹的高度 為 [logN] + 1(只有根節點的樹高度為0) .?

    下面是區間 [0, 9]? 的一個線段樹:?

    ?

    線段樹和堆有一樣的結構, 因此如果一個節點編號為 x ,那么左孩子編號為2*x? ?右孩子編號為2*x+1.?

    使用線段樹解決RMQ問題,關鍵維護一個數組M[num],num=2^(線段樹高度+1).?
    M[i]:維護著被分配給該節點(編號:i 線段樹根節點編號:1)的區間的最小值元素的下標。 該數組初始狀態為-1.?

    /***?@brief???????????segment?stree*?@author??????????xiyan*?@date????????????2014/6/17*?@last*/ #include?<iostream> #include?<cstdlib> #include?<cstring> namespace?rmq { using?namespace?std; typedef?unsigned?int?size_t; typedef?signed???int?ssize_t; static?ssize_t?inline??getLftNode(const?ssize_t?idx) {return?(idx?<<?1); } static?ssize_t?inline??getRhtNode(const?ssize_t?idx) {return?((idx?<<?1)?+?1); } template<typename?T> class?segmentTree { public:segmentTree(void):deps(0),?nodes(0),?elems(0),?tree(NULL)?{}ssize_t?createSt(const?T?*input,?const?ssize_t?cnt);~segmentTree(void){destorySt();}const?T?*?searchSt(const?ssize_t?lftQuery,?const?ssize_t?rhtQuery);virtual?void?debug(void); private:ssize_t?allocSt(const?ssize_t?cnt);ssize_t?initSt(const?T?*input);ssize_t?initNode(const?ssize_t?nodeIdx,?const?ssize_t?lftIdx,?const?ssize_t?rhtIdx,?const?T?*input);const?T?*searchNode(const?ssize_t?nodeIdx,?const?ssize_t?lftIdx,?const?ssize_t?rhtIdx,?\const?ssize_t?lftQuery,?const?ssize_t?rhtQuery);void?destorySt(void);ssize_t?log(const?ssize_t?x)?const;bool?checkPow(const?ssize_t?x)?const;T?*tree;ssize_t?deps;?????????????????????????????????/*dep?of?the?tree*/ssize_t?nodes;????????????????????????????????/*nodes?tots*/ssize_t?elems;????????????????????????????????/*element?tots*/ }; /***?@brief?2^n?<=?x,?return?n;*?@return?n?success,?-1?fail**/ template<typename?T> ssize_t?segmentTree<T>::log(const??ssize_t?x)?const {ssize_t?ans??=?0;ssize_t?cnt?=?x;if(cnt?<=?0){return?-1;}while(?(1?<<?ans)?<=?cnt){++ans;}ans--;return?ans; } /***?@brief?make?sure?the?input?is?pow?of?2*?@return?n?success,?-1?fail**/ template<typename?T> bool?segmentTree<T>::checkPow(const??ssize_t?x)?const {if(x?<=?0){return?false;???/*x?<=?0*/}if(!(x?&?(x?-?1))){return?true;????/*x?==?2^n*/}else{return?false;???/*x?>?0?&&?x?!=?2^n*/} } /***?@brief?get?the?dep?and?the?size?for?tree*?@param[in]?cnt?tots?of?the?input?to?build?tree**/ template<typename?T> ssize_t?segmentTree<T>::allocSt(const?ssize_t?cnt) {if(cnt?<=?0){return?-1;}ssize_t?depTmp?=?log(cnt);if(depTmp?<?0){return?-1;}if(!checkPow(cnt)){depTmp++;}depTmp++;ssize_t?nodeTots?=?(1?<<?depTmp)?-?1;???/*nodes?needed?*/nodeTots++;?????????????????????????????/*add?empty?node?at?head*/tree?=?new?T[nodeTots];if(!tree){return?-1;}memset(tree,?0,?nodeTots);deps???=?depTmp;??????????????????????/*store?cnt*/nodes??=?nodeTots;elems??=?cnt;return?0; }; /***?@brief?init?tree**/ template<typename?T> ssize_t?segmentTree<T>::initSt(const?T?*input) {const?ssize_t?rootNode?=?1;const?ssize_t?lftIdx???=?0;const?ssize_t?rhtIdx???=?elems?-?1;if(initNode(rootNode,?lftIdx,?rhtIdx,?input)?<?0){return?-1;}return?0; } /***?@brief?init?node?and?continue?to?build?children*?@param[in]?nodeIdx?curr?node*?@param[in]?lftIdx?start?idx?for?input*?@param[in]?rhtIdx?end?idx??for?input*?@param[in]?store?for?input*?@return?-1?error*?????????0??success*/ template<typename?T> ssize_t?segmentTree<T>::initNode(const?ssize_t?nodeIdx,?const?ssize_t?lftIdx,?const?ssize_t?rhtIdx,?const?T?*input) {//cout?<<?"nodeIdx?=?"?<<?nodeIdx?<<?","?<<?"nodes?="?<<?nodes?<<?endl;??cout?<<?lftIdx?<<?"?"<<?rhtIdx?<<?endl;if(nodeIdx?>=?nodes)?????/*segment?error*/{return?-1;}if(lftIdx?==?rhtIdx){tree[nodeIdx]?=?input[lftIdx];return?0;}ssize_t?midIdx?=?(lftIdx?+?rhtIdx)?>>?1;ssize_t?curNode?=?nodeIdx;ssize_t?lftNode?=?getLftNode(curNode);ssize_t?rhtNode?=?getRhtNode(curNode);if(initNode(lftNode,?lftIdx,?midIdx,?input)?<?0){return?-1;}if(initNode(rhtNode,?midIdx?+?1,?rhtIdx,?input)?<?0){return?-1;}tree[curNode]?=?(tree[lftNode]?<?tree[rhtNode]???tree[lftNode]?:?tree[rhtNode]);return?0; } /***?@brief?create?segment?tree*?@param[in]?input?elems?used?to?build?segment?tree*?@param[in]?cnt???tot?nums?of?elems*?@return?0?success,?-1?fail*/ template<typename?T> ssize_t?segmentTree<T>::createSt(const?T?*input,?const?ssize_t?cnt) {if(allocSt(cnt)?<?0){cout?<<?"alloc?space?for?segment?tree?fail"?<<?endl;return?-1;}if(initSt(input)?<?0){cout?<<?"init?segment?tree?fail"?<<?endl;return?-1;}return?0; } /***?@brief?search?ans?for?the?query?range*?@param[in]?nodeIdx?node?index*?@param[in]?lftIdx??lft?index?for?data?store*?@param[in]?rhtIdx??rht?index?for?data?store*?@param[in]?lftQuery?lft?for?query?range*?@param[in]?rhtQuery?rht?for?query?range*/ template<typename?T> const?T?*?segmentTree<T>::searchNode(const?ssize_t?nodeIdx,?const?ssize_t?lftIdx,?const?ssize_t?rhtIdx,?\const?ssize_t?lftQuery,?const?ssize_t?rhtQuery) {if(lftIdx?>?rhtQuery?||?rhtIdx?<?lftQuery){return?NULL;}if(?lftQuery?<=?lftIdx?&&?rhtQuery?>=?rhtIdx){return?(&tree[nodeIdx]);}ssize_t?midIdx?=?(lftIdx?+?rhtIdx)?>>?1;ssize_t?curNode?=?nodeIdx;ssize_t?lftNode?=?getLftNode(curNode);ssize_t?rhtNode?=?getRhtNode(curNode);const?T??*lftans?=?searchNode(lftNode,?lftIdx,?midIdx,?lftQuery,?rhtQuery);const?T??*rhtans?=?searchNode(rhtNode,?midIdx?+?1,?rhtIdx,?lftQuery,?rhtQuery);if(!lftans){return?rhtans;}if(!rhtans){return?lftans;}return?(*lftans??<?*rhtans???lftans?:?rhtans); } template<typename?T> const?T?*?segmentTree<T>::searchSt(const?ssize_t?lftQuery,?const?ssize_t?rhtQuery) {if(lftQuery?<?0?||?rhtQuery?>=?elems?||?lftQuery?>?rhtQuery){return?NULL;}const?T?*ans;const?ssize_t?rootNode?=?1;const?ssize_t?lftIdx???=?0;const?ssize_t?rhtIdx???=?elems?-?1;if(?NULL?==?(ans?=?searchNode(rootNode,?lftIdx,?rhtIdx,?lftQuery,?rhtQuery))){return?NULL;}return??ans; } /***?@brief?destory?the?array?for?store?tree**/ template<typename?T> void?segmentTree<T>::destorySt(void) {delete?tree;deps?=?0;nodes?=?0;elems?=?0; } /***?@brief?debug?segment?tree**/ template<typename?T> void?segmentTree<T>::debug(void) {cout?<<?"deps?:??"?<<?deps??<<?endl;cout?<<?"nodes:??"?<<?nodes?<<?endl;cout?<<?"elems:??"?<<?elems?<<?endl; } }

    ?

    參考文章

    ?

  • http://blog.csdn.net/huangxy10/article/details/7945856

  • http://blog.163.com/zhaohai_1988/blog/static/209510085201263011135062/


  • 轉載于:https://my.oschina.net/u/572632/blog/280347

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。