關於一個小問題的聯想

潮溼的天氣和人的心理一樣,散發出懶洋洋的熱空氣。懶的寫東西,帖一篇Love_Shsean的文。

我們設柱型圖的元素高度爲h [ ],那麼我們要求的就是max { h [i] * (Right [i] - Left [i] + 1) },其中Left [i]分別是以h [i]爲中心,向左拓展使得h [j]~ h [i] <= h [i]的最大j,Right [i]也有類似的定義。查看更多精彩圖片

由此,我們來看一個子問題:已知數組h, 如何求Left [ ]。
算法1、枚舉,O (N ^ 2)。
算法2、線段樹,O (N Log N)。
算法3、用已經計算出的結果來加速當前的計算。
顯然有這樣的結論,如果當前計算的i (i > 0),h [i] > h [i - 1],顯然Left [i] = i,否則我們要比較h [i - 2] 和 h [i],那麼如果我們已知了Left [ i - 1],能不能用Left [i - 1]的結果來省去一些不必要的比較呢?
h [i] <= h [i - 1], h [i - 1] <= h [ Left [ i - 1] ] ,於是我們只要從Left [i - 1] - 1開始和h [i]比較就行了,省去了中間不必要的比較,同樣的道理,我們可以一直迭代的來比較。代碼只有兩行:
for (i = 0; i < N; i ++)
   for (Left [i] = i; Left [i] && h [Left [i] - 1] >= h [i]; Left [i] = Left [Left [i] - 1]);
極爲簡潔,O (N * Log*N) 已經很接近於O (N)了。
算法4、
在看算法4之前,我們先來看Zoj 1985的官方解法。

Linear search using a stack of incomplete subproblems
We process the elements in left-to-right order and maintain a stack of information about started but yet unfinished subhistograms. Whenever a new element arrives it is subjected to the following rules. If the stack is empty we open a new subproblem by pushing the element onto the stack. Otherwise we compare it to the element on top of the stack. If the new one is greater we again push it. If the new one is equal we skip it. In all these cases, we continue with the next new element.
If the new one is less, we finish the topmost subproblem by updating the maximum area w.r.t. the element at the top of the stack. Then, we discard the element at the top, and repeat the procedure keeping the current new element. This way, all subproblems are finished until the stack becomes empty, or its top element is less than or equal to the new element, leading to the actions described above. If all elements have been processed, and the stack is not yet empty, we finish the remaining subproblems by updating the maximum area w.r.t. to the elements at the top.
For the update w.r.t. an element, we find the largest rectangle that includes that element. Observe that an update of the maximum area is carried out for all elements except for those skipped. If an element is skipped, however, it has the same largest rectangle as the element on top of the stack at that time that will be updated later.
The height of the largest rectangle is, of course, the value of the element. At the time of the update, we know how far the largest rectangle extends to the right of the element, because then, for the first time, a new element with smaller height arrived. The information, how far the largest rectangle extends to the left of the element, is available if we store it on the stack, too.
We therefore revise the procedure described above. If a new element is pushed immediately, either because the stack is empty or it is greater than the top element of the stack, the largest rectangle containing it extends to the left no farther than the current element. If it is pushed after several elements have been popped off the stack, because it is less than these elements, the largest rectangle containing it extends to the left as far as that of the most recently popped element.
Every element is pushed and popped at most once and in every step of the procedure at least one element is pushed or popped. Since the amount of work for the decisions and the update is constant, the complexity of the algorithm is O(n) by amortized analysis.

這個解法維護了一個棧,遞歸地以O (N)的時間計算出了結果。
看一下代碼吧:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章