intlargestRectangleArea(vector<int>& heights){ int n = height.size(); int res = 0; for (int i = 0; i < n; ++i) { for (int j = i; j < n; j++) { int minv = INF; for (int k = i; k <= j; ++k) { minv = min(minv, height[k]); } res = max(res, (i - j + 1) * minv); } } return res; }
classSolution { public: intlargestRectangleArea(vector<int>& heights){ vector<int> s(heights.size() + 2); vector<int> w(heights.size() + 2); int p = 0;
heights.push_back(0); int res = 0; for (int i = 0; i < heights.size(); ++i) { if (heights[i] > s[p]) { s[++p] = heights[i]; w[p] = 1; } else { int width= 0; while (s[p] > heights[i]) { width += w[p]; res = max(res, width * s[p]); p--; } s[++p] = heights[i]; w[p] = width + 1; } } return res; } };vf
publicclassSolution { publicintcalculateArea(int[] heights, int start, int end){ if (start > end) return0; int minindex = start; for (int i = start; i <= end; i++) if (heights[minindex] > heights[i]) minindex = i; return Math.max(heights[minindex] * (end - start + 1), Math.max(calculateArea(heights, start, minindex - 1), calculateArea(heights, minindex + 1, end))); } publicintlargestRectangleArea(int[] heights){ return calculateArea(heights, 0, heights.length - 1); } }
intlargestRectangleArea(vector<int>& heights){ int n = height.size(); int res = 0; for (int i = 0; i < n; ++i) { int minv = height[i]; for (int j = i; j < n; j++) { //确保j从小变大 int minv = INF; //如果i看作一个定值,下面这个循环,其实每次都做了相同的工作,重复扫描[i, j] //所以可以做累计处理 //for (int k = i; k <= j; ++k) { // minv = min(minv, height[k]); //} minv = min(minv, height[j]); res = max(res, (i - j + 1) * minv); } } return res; }
inttrap(vector<int>& height){ int n = height.size(); int res = 0; for (int i = 1; i < n; ++i) {
//往左找到最大值 int lmax = 0; for (int j = 0; j < i; ++j) { lmax = max(lmax, height[j]); }
//往右找到最大值 int rmax = 0; for (int j = i + 1; j < i; ++j) { rmax = max(rmax, height[j]); }
res += min(rmax, lmax) - height[i];
} }
时间复杂度:$O(n^2)$ 空间复杂度:$O(1)$
接雨水问题-进一步思考
观察上面的代码,有很多重复计算,例如计算i左边的最大值时,扫描范围是[0, i - 1];当计算i+1左边的最大值时,扫描范围是[0, i],显然是完全包含[0, i - 1]的, 对于重复计算,我们继续采用空间换时间的套路,用数组lmax[i]来存储[0, i - 1]的最大值;这样子存储之后,如果再计算lmax[i + 1]只要拿lmax[i]跟height[i + 1]比较即可。
接雨水问题-空间换时间版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
inttrap(vector<int>& height){ int n = height.size(); int res = 0; int lmax[N], rmax[N]; //正序遍历 for (int i = 1; i < n; ++i) { lmax[i] = max(lmax[i - 1], height[i - 1]); }
//倒序遍历 for (int i = n; i >= 0; --i) { rmax[i] = max(rmax[i + 1], height[i + 1]); }
for (int i = 1; i < n; ++i) { res += min(lmax[i], rmax[i]) - height[i]; } }
classSolution { public: /** * max water * @param arr int整型vector the array * @return long长整型 */ longlongmaxWater(vector<int>& arr){ stack<int> s; s.push(-1); int res = 0; for (int i = 0; i < arr.size(); ++i) { while (s.top() != -1 && arr[s.top()] < arr[i]) { int cur = s.top(); //当前计算的格子 s.pop(); int left = s.top(); if (left >= 0) { res += (min(arr[left], arr[i]) - arr[cur]) * (i - left - 1); //cout << "i:" << i << ", cur:" << cur << ", res: " << res << endl; } }
intlongestSubstringWithoutDuplication(string s){ int i, j = 0, n =s.size(); unordered_map<char,int> counter; int res = 0; while (i < n) { char c = s[i]; counter[c]++; if (counter[c] == 1) { //新来了一个不重复元素,则窗口扩大了 res = max(res, i - j + 1) } i++; while (j < i && counter[c] > 1) { //如果现在窗口已经不在符合条件,则一直往前移动left,直到窗口重新满足 counter[s[j]]--; j++; } } }