单调栈——子数组范围和
原题在这里。
概述:求给定数组的 所有子数组的极差 之和。
基本暴力:
class Solution { public: long long subArrayRanges(vector<int> &nums) { long long ans = 0, l = nums.size(); int mx, mi; for (int i = 0; i < l; ++i) { mx = mi = nums[i]; for (int j = i + 1; j < l; ++j) { mx = max(mx, nums[j]); mi = min(mi, nums[j]); } ans += mx - mi; } return ans; } };
要求进阶算法的复杂度为O(n),
进一步思考,
要求所有极差之和,换句话说,就是找子数组内的最大元素之和减去最小元素之和
因为所有子数组都会考虑,所以可以换成:
考虑每一个数字作为最大/最小值的次数,进行累加累减即可
那么,转换成公式就是
对于元素nums[i],在区间[l,r]中,对最终答案有ans(+/-)=(i - l + 1) * (r - i + 1) * nums[i]
然后就是找区间最值的问题了,这里就用单调栈
tips:
1.最大最小相关,就应该想到单调栈
2.求最大元素,用递减栈;求最小元素,用递增栈
3.求左边的最值,应从左往右遍历;求右边最值,从右往左遍历(理应这样,也不一定)
【关键是怎么使用单调栈】
我即便是已经知道用单调栈还是没想明白怎么写那个逻辑,还是经验+智慧不足了。
1.找区间范围,所以入栈元素应该是下标
2.怎么考虑左右端点的出栈or入栈情况,
对于找nums[i]为最大值的区间,误!!!
      就是这里没想明白,起点应该是对于一个单调栈的top元素
   对于(找最大元素的递减栈)nums[stack.top()],如果nums[i]值更大,那么top出栈,
此时,可以确定,top范围区间为
左区间[stack[top-1],stack.top()] + 右区间[stack.top(),i]
   ----------------------------------------------
对于(找最小元素的递增栈)nums[stack.top()],如果nums[i]值更小,那么top出栈,
区间也是一样的处理
【OVER】
下面就上代码:
class Solution { public: long long subArrayRanges(vector<int> &nums) { long long ans = 0, len = nums.size(); for (int i = 0, l, r; i < len; i++) { //最大 l = r = i; while (l - 1 >= 0 && nums[l - 1] <= nums[i]) l--; while (r + 1 < len && nums[r + 1] < nums[i]) r++; ans += (i - l + 1) * (r - i + 1) * (long long)nums[i]; //最小 l = r = i; while (l - 1 >= 0 && nums[l - 1] >= nums[i]) l--; while (r + 1 < len && nums[r + 1] > nums[i]) r++; ans -= (i - l + 1) * (r - i + 1) * (long long)nums[i]; } return ans; } };
normal:
class Solution { long long maxsum(vector<int> nums) { long long ans = 0, l = nums.size(); stack<int> st; for (int i = 0; i <= l; ++i) { while (!st.empty() && (i == l || nums[st.top()] < nums[i])) { int last1 = st.top(); st.pop(); int last2 = st.empty() ? -1 : st.top(); ans += (long long)nums[last1] * (i - last1) * (last1 - last2); } st.push(i); } return ans; } long long minsum(vector<int> nums) { long long ans = 0, l = nums.size(); stack<int> st; for (int i = 0; i <= l; ++i) { while (!st.empty() && (i == l || nums[st.top()] > nums[i])) { int last1 = st.top(); st.pop(); int last2 = st.empty() ? -1 : st.top(); ans += (long long)nums[last1] * (i - last1) * (last1 - last2); } st.push(i); } return ans; } public: long long subArrayRanges(vector<int> &nums) { return maxsum(nums) - minsum(nums); } };
精简:
class Solution { long long sum(vector<int> nums, bool pd) { long long ans = 0, l = nums.size(); stack<int> st; for (int i = 0; i <= l; ++i) { while (!st.empty() && (i == l || (nums[st.top()] > nums[i] && !pd) || (nums[st.top()] < nums[i] && pd))) { int last1 = st.top(); st.pop(); int last2 = st.empty() ? -1 : st.top(); ans += (long long)nums[last1] * (i - last1) * (last1 - last2); } st.push(i); } return ans; } public: long long subArrayRanges(vector<int> &nums) { return sum(nums, 1) - sum(nums, 0); } };
                    
                
                
            
        
浙公网安备 33010602011771号