给定一个数组arr, 返回所有子数组最小值的累加和
import java.util.Stack;
public class SumOfSubarrayMinimums {
public static void main(String[] args) {
//int[] arr = {3,2,4};
for (int i = 0; i < 10000; i++) {
int[] arr = generateRondomArray();
int ans1 = subArrayMinSum2(arr);
int ans2 = subArrayMins(arr);
if(ans1 != ans2){
System.out.println("false");
break;
}else{
System.out.println(i +" "+arr.length+" "+ans1+" "+ans2+" "+" true");
}
}
}
// 非单调栈模式
public static int subArrayMinSum2(int[] arr){
// left[i]=x : x表示一个索引位置就是这个位置的数是在arr[i]左边,且离arr[i]最近, 且arr[x] <= arr[i]的位置.
int[] left = leftNearLessEqual2(arr);
// right[i]=y : y表示一个索引位置就是这个位置的数是在arr[i]右边,且离arr[i]最近, 且arr[x] > arr[i]的位置.
int[] right = rightNearLessEqual2(arr);
int sum = 0;
for (int i = 0; i < arr.length; i++) {
int start = left[i];
int end = right[i];
sum += (i-start)*(end-i)*arr[i];
}
return sum;
}
public static int[] leftNearLessEqual2(int[] arr){
int[] left = new int[arr.length];
left[0] = -1;
for (int i = 1; i < arr.length; i++) {
int ans = -1;
for (int j = i-1; j >=0 ; j--) {
if(arr[j] <= arr[i]){
ans = j;
break;
}
}
left[i] = ans;
}
return left;
}
public static int[] rightNearLessEqual2(int[] arr){
int[] right = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
int ans = arr.length;
for (int j = i+1; j < arr.length ; j++) {
if(arr[j] < arr[i]){
ans = j;
break;
}
}
right[i] = ans;
}
return right;
}
// 单调栈
public static int subArrayMins(int[] arr){
// left[i]=x : x表示一个索引位置就是这个位置的数是在arr[i]左边,且离arr[i]最近, 且arr[x] <= arr[i]的位置.
int[] left = nearLessEqualLeft(arr);
// right[i]=y : y表示一个索引位置就是这个位置的数是在arr[i]右边,且离arr[i]最近, 且arr[x] > arr[i]的位置.
int[] right = nearLessRight(arr);
int sum = 0;
for (int i = 0; i < arr.length; i++) {
int start = left[i];
int end = right[i];
sum += (i-start)*(end-i)*arr[i];
}
return sum;
}
public static int[] nearLessEqualLeft(int[] arr){
int[] left = new int[arr.length];
Stack<Integer> stack = new Stack<>();
for (int i = arr.length-1; i >= 0 ; i--) {
while(!stack.isEmpty() && arr[stack.peek()]>=arr[i]){
int popIndex = stack.pop();
left[popIndex] = i;
}
stack.push(i);
}
while (!stack.isEmpty()){
int popIndex = stack.pop();
left[popIndex] = -1;
}
return left;
}
public static int[] nearLessRight(int[] arr){
int[] right = new int[arr.length];
Stack<Integer> stack = new Stack<>();
for (int i = 0 ; i < arr.length ; i++) {
while(!stack.isEmpty() && arr[stack.peek()]>arr[i]){
int popIndex = stack.pop();
right[popIndex] = i;
}
stack.push(i);
}
while (!stack.isEmpty()){
int popIndex = stack.pop();
right[popIndex] = arr.length;
}
return right;
}
public static int[] generateRondomArray(){
int[] arr = new int[(int)(Math.random() * 20) + 10];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random() * 101);
}
return arr;
}
}