好难啊,研究了一个下午了救命!!!
遍历a[i] 计算dp[i] dp[i]——以a[i]为右边界的min值总和
以a[i]结尾时,分两种情况:
- 所有的子数组都以a[i]为最小值
比如[3,0] 此时以a[i]=0为右边界的子数组为[0] [3,0]
则此时的 dp[i]=(i+1)*a[i] 也就是dp[1]=(1+1)*0=0
- 有一部分子数组以a[i]为最小值,另一部分子数组以前面一个比a[i]更小的数为最小值
比如[3,0,4,2,1] 此时[4,2,1]部分以a[i]为最小值 [1] [2,1] [4,2,1]
所以这一部分的值为3*a[i]=3,我们可以用单调栈找到离a[i]最近的比它小的值的下标
(i - j)*a[i]
而前一段[3,0]部分则在之前算过了,也就是dp[j]=dp[1]=0
所以这一段结果就是:dp[i]=dp[j]+(i - j)*a[i]
最后累加每一次的dp[i]即可
class Solution {
//动态规划 dp[i]:a[i] 为右边界的min总和
public int sumSubarrayMins(int[] arr)
{
int len=arr.length;
int res=0;
int mod=1000000007;
int[] dp= new int[len];
dp[0]=arr[0];
Deque<Integer> st=new LinkedList<>();
for(int i=0; i<len;i++)
{
while(!st.isEmpty()&&arr[st.peek()]>arr[i]) st.pop();//保证单调递增 找离它最近的比它小的值
if(!st.isEmpty())
{
int j=st.peek();
dp[i]=dp[j]+(i - j)*arr[i]; //j+1~i这一段以a[i]为最小值 0~j这一段以a[j]为最小值
}else
dp[i]=(i + 1)*arr[i]; //以a[i]为右边界的子数组都是a[i]为最小值
res=(res+dp[i])%mod;//累加dp得到结果
st.push(i);
}
return res;
}
}