2009年2月7日

Range Minimum(Maximum) Query, RMQ

  • Input:array A[0, N]
  • Output: the index of minimum(maximum) value between two given indices.

RMQ的功能是若有一群資料放在array中,在經過preprocessing後,可在O(1)的時間內找出index i~j之間的最小(大)的元素。目前preprocessing最快是O(n),也就是只需要O(n)的時間就可以處理完成。

以下介紹O(nlog(n))的preprocessing方法,O(n)的方法是由此法去改進,所以先了解此法相當重要且因程式碼容易撰寫,所以也相當適合在ACM中使用。

  1. 假設array的長度2的n次方。
  2. 建立一個大小為n x log(n)的矩陣M,用來存放RMQ的結果,其中M[i][j]是指以index i開頭,長度為2^j次方內最小元素的index。
  3. 使用dynamic programming方法建立M,需O(nlogn) time。
RMQ_003 image
RMQ_007

 

  1. //time complexity: O(nlogn)
  2. void preprocess(int M[MAXN][LOGMAXN], int A[MAXN], int N)
  3. {
  4.     int i, j;
  5.  
  6.     //initialize M for the intervals with length 1
  7.     for (i = 0; i < N; i++)
  8.         M[i][0] = i;
  9.     //compute values from smaller to bigger intervals
  10.     for (j = 1; 1 << j <= N; j++)
  11.         for (i = 0; i + (1 << j) - 1 < N; i++)
  12.             if (A[M[i][j - 1]] < A[M[i + (1 << (j - 1))][j - 1]])
  13.                 M[i][j] = M[i][j - 1];
  14.             else
  15.                 M[i][j] = M[i + (1 << (j - 1))][j - 1];
  16. }

RMQ_005 

  1. //output: the index of the minimum value between index i and j
  2. int RMQ(int i, int j, int M[MAXN][LOGMAXN], int A[MAXN], int N)
  3. {
  4.     if(i<0 || i>=N || j<0 || j>=N)
  5.         return -1;
  6.  
  7.     if(i > j) //swap i, j
  8.         i ^= j, j ^= i, i ^= j;
  9.  
  10.     int k   = (int)(log(j-i)/log(2.0)),
  11.         rem = j-(1<<k) + 1;
  12.     return (A[M[i][k]] > A[M[rem][k]] ? M[rem][k] : M[i][k]);
  13. }

Reference: