left[i]:以arr[i]元素为最右且最小的子序列数目
right[i]:以arr[i]元素为最左且最小的子序列数目
对于每一个arr[i],
class Solution {
public int sumSubarrayMins(int[] arr) {
int n=arr.length;
int[] left=new int[n];
int[] right=new int[n];
Deque<Integer>stack=new ArrayDeque<>();
//计算left
for(int i=0;i<n;i++){
while(!stack.isEmpty()&&arr[i]<=arr[stack.peek()])
stack.poll();
if(!stack.isEmpty())
left[i]=i-stack.peek();
else
left[i]=i+1;
stack.push(i);
}
stack.clear();
//计算right
for(int i=n-1;i>=0;i--){
while(!stack.isEmpty()&&arr[i]<arr[stack.peek()])
stack.poll();
if(!stack.isEmpty())
right[i]=stack.peek()-i;
else
right[i]=n-i;
stack.push(i);
}
//计算结果
long res=0;
final int MOD=1000000007;
for(int i=0;i<n;i++){
res=(res+(long)left[i]*right[i]*arr[i])%MOD;
}
return (int)res;
}
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
状态定义:s[i][j] 表示子数组[ arr[j], arr[j+1],…,arr[i] ]的最小值
状态转移方程:
假设以arr[i]为最右且最小的最长子序列长度为k:
j>=i-k+1时,s[j][i]=arr[i]
j
初始条件:
dp[i]=0
返回值:dp[i] 的和,0<=i<=n-1
算法
class Solution {
public int sumSubarrayMins(int[] arr) {
int n=arr.length;
int[] dp=new int[n];
long res=0;
final int MOD=1000000007;
Deque<Integer>stack=new ArrayDeque<>();
for(int i=0;i<n;i++){
//维护单调栈
while(!stack.isEmpty()&&arr[i]<=arr[stack.peek()])
stack.poll();
int k=stack.isEmpty()?i+1:i-stack.peek();//以arr[i]为最右且最小的最长子序列长度
dp[i]=k*arr[i]+(stack.isEmpty()?0:dp[i-k]);
res=(res+dp[i])%MOD;
stack.push(i);
}
return (int)res;
}
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)