您的位置:首页 > 其它

LeetCode Largest Rectangle in Histogram

2014-04-14 23:57 267 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: