zoukankan      html  css  js  c++  java
  • LeetCode Largest Rectangle in Histogram

    class SegmentTree {
        private:
            int *mem;
            int *idx;
            int capacity;
            int storage_size;
    
        private:
            void init_level_update() {
                int k = capacity - 1;
                while (--k >= 0) {
                    int L = (k<<1) + 1;
                    int R = L + 1;
                    if (mem[L] < mem[R]) {
                        mem[k] = mem[L];
                        idx[k] = idx[L];
                    } else {
                        mem[k] = mem[R];
                        idx[k] = idx[R];
                    }
                }
            }
    
            pair<int, int> query(int a, int b, int idx, int L, int R) {
                if (b <= L || a >= R) return make_pair(INT_MAX, -1);
                if (a <= L && R <= b) return make_pair(mem[idx], this->idx[idx]);
    
                pair<int, int> ml = query(a, b, (idx<<1) + 1, L, (L+R)/2);
                pair<int, int> mr = query(a, b, (idx<<1) + 2, (L+R)/2, R);
                if (ml.second == -1) return mr;
                if (mr.second == -1) return ml;
                return ml.first < mr.first ? ml : mr;
            }
    
            void init_mem(int _capacity) {
                if (_capacity <= 0) {
                    capacity = 0;
                    return;
                }
                int n = 1;
                while (n < _capacity) n<<=1;
                capacity = n;
                storage_size = capacity * 2 - 1;
                mem = new int[storage_size];
                idx = new int[storage_size];
                
                int k = 0;
                while (k < storage_size) mem[k++] = INT_MAX;
                k = capacity - 1;
                int i = 0;
                while (k < storage_size) idx[k++] = i++;
            }
        public:
            SegmentTree(int _capacity) {
                init_mem(_capacity);
            }
            SegmentTree(vector<int>::iterator begin, vector<int>::iterator end) {
                capacity = end - begin;
                init_mem(capacity);
    
                int k = capacity - 1;
                vector<int>::iterator iter = begin;
                while (iter != end) mem[k++] = *iter++;
    
                init_level_update();
            }
    
            ~SegmentTree() {
                delete[] mem;
                delete[] idx;
            }
    
            // update value in original data index
            void update(int index, int val) {
                if (index >= capacity || idx < 0) return;
                int k = index + capacity - 1; // internal storage index
                mem[k] = val;
                while (k > 0) {
                    k = (k - 1) >> 1;
                    int L = (k << 1) + 1;
                    int R = L + 1;
                    if (mem[L] < mem[R]) {
                        mem[k] = mem[L];
                        idx[k] = idx[L];
                    } else {
                        mem[k] = mem[R];
                        idx[k] = idx[R];
                    }
                }
            }
    
            // retrive the min value in index range [a, b)
            pair<int, int> query(int a, int b) {
                return query(a, b, 0, 0, capacity);
            }
    
            void print_mem(const char* msg) {
                cout<<msg<<endl;
                for (int i=0; i<(capacity*2-1); i++) {
                    cout<<mem[i]<<" ";
                }
                
                for (int i=0; i<capacity * 2 - 1; i++) {
                    cout<<idx[i]<<",";
                }
                cout<<endl;
            }
    };
    
    class Solution {
    private:
        SegmentTree* seg_tree;
    public:
        // this brute-force method will case TLE
        int bf_largestRectangleArea(vector<int> &height) {
            vector<bool> visited(height.size(), false);
            int len = height.size();
            int max_area = 0;
            for (int i=0; i<len; i++) {
                int ch = height[i];
                int range = 1;
                if (visited[i]) continue;
                for (int j = i - 1; j >= 0; j--) {
                    if (height[j] < ch) break;
                    if (height[j] == ch) visited[j] = true;
                    range++;
                }
                for (int j = i + 1; j < len; j++) {
                    if (height[j] < ch) break;
                    if (height[j] == ch) visited[j] = true;
                    range++;
                }
                if (range * ch > max_area) max_area = range * ch;
            }
            return max_area;
        }
        
        int largestRectangleArea(vector<int> &height) {
            seg_tree = new SegmentTree(height.begin(), height.end());
            int maxarea = dfs(0, height.size());
            delete seg_tree;
            return maxarea;
        }
        
        int dfs(int L, int R) {
            int ret = 0;
            if (L >= R) return ret;
            pair<int, int> res = seg_tree->query(L, R);
            ret = (R - L) * res.first;
            int ml = dfs(L, res.second);
            int mr = dfs(res.second + 1, R);
            return max(ret, max(ml, mr));
        }
    };

    人艰不拆,趁机学习了一下线段树,180+ms,数据多的情况下(如大量连续递增序列)有可能造成栈溢出

    找到一个巧妙的O(n)解法

    class Solution {
    public:
        int largestRectangleArea(vector<int> &height) {
            int len = height.size();
            if (len == 0) return 0;
            int maxarea = height[0], area;
            vector<int> stack;
            int pos = 0, idx;
            while (pos<len) {
                if (stack.empty() || height[stack.back()] <= height[pos]) {
                    stack.push_back(pos++);
                } else {
                    idx = stack.back();
                    stack.pop_back();
                    area = height[idx] * (stack.empty() ? pos : pos - stack.back() - 1);
                    if (area > maxarea) maxarea = area;
                }
            }
            
            while (!stack.empty()) {
                idx = stack.back();
                stack.pop_back();
                area = height[idx] * (stack.empty() ? pos : pos - stack.back() - 1);
                if (maxarea < area) maxarea = area;
            }
            
            return maxarea;
        }
    };

    100+ms

    后来看了zhuli哥的解法,感觉更自然一点,就是先求出两个数组L,R,他们存储了从位置i开始向左/右不小于height[i]的且中间不被隔断的最远的一条bar的索引值,求的过程中可以复用以前的结果,这样就比暴力的找两个端点高效很多,时间也是这几种方法里最快的。下面给出代码:

    class Solution {
    public:
        int largestRectangleArea(vector<int> &height) {
            int len = height.size();
            if (len == 0) return 0;
            int maxarea = 0;
            vector<int> L, R;
            L.resize(len), R.resize(len);
            for (int i=0; i<len; i++) {
                L[i] = i;
                while (L[i]-1 >= 0 && height[L[i]-1] >= height[i]) {
                    L[i] = L[L[i] - 1];
                }
            }
            int area;
            for (int i=len-1; i>=0; i--) {
                R[i] = i;
                while (R[i]+1 <= len-1 && height[R[i]+1] >= height[i]) {
                    R[i] = R[R[i] + 1];
                }
                area = (R[i] - L[i] + 1) * height[i];
                if (area > maxarea) maxarea = area;
            }
            return maxarea;
        }
    };

    60ms+

    感觉关键还是怎么样去分解问题,把其中的效率瓶颈解决掉,另外简单最美

    这回用下那个是用stack的版本的解法,似乎要好理解一些,同时也适用于很多类似的问题

    class Solution {
    public:
        int largestRectangleArea(vector<int>& height) {
            height.push_back(0);
            int len = height.size();
            stack<int> pos;
            int maxarea = 0;
            for (int i=0; i<len; i++) {
                while (!pos.empty() && height[i] < height[pos.top()]) {
                    int last = pos.top();
                    pos.pop();
                    
                    int w = i - (pos.empty() ? -1 : pos.top()) - 1;
                    int h = height[last];
                    
                    maxarea = max(w * h, maxarea);
                }
                pos.push(i);
            }
            return maxarea;
        }
    };

    参考:

      http://www.geeksforgeeks.org/largest-rectangular-area-in-a-histogram-set-1/

      http://www.geeksforgeeks.org/largest-rectangle-under-histogram/

      http://www.cnblogs.com/zhuli19901106/p/3568217.html

      http://www.julyedu.com/course/index/category/algorithm.html

  • 相关阅读:
    视频实例分割 | Target-Aware Adaptive Tracking for Unsupervised Video Object Segmentation
    目标检测算法:Selective Search(选择性搜索)简述
    [2020BUAA软工助教]期末总结
    WPF,数据验证方案,验证通过才能继续下一步
    WPF:解决数据验证ValidationRule与按钮Canexcute联动的问题
    解决mininet运行报错“ImportError: No module named mininet.log”
    交易所对接ERC20钱包端口要多长时间?
    尺子的刻度
    学习java的第四周
    学习java的第三周
  • 原文地址:https://www.cnblogs.com/lailailai/p/3665263.html
Copyright © 2011-2022 走看看