给定一个只包含正数的数组arr, arr中任何一个子数组sub,一定都可以算出(sub累加和)*(sub中的最小值)是什么,那么所有子数组中,这个值最大是多少?
import java.util.Stack;
public class AllTimesMinToMax {
public static void main(String[] args) {
//int[] arr = {12,4,5,2,2,5,6,7,8,9,1,6,4,1,4,7,8,9};
//int[] arr = {1,2,2,2,2,2,2,2,2,1};
for (int i = 0; i < 1000; i++) {
int[] arr = generateRondomArray();
int r1 = max1(arr);
int r2 = max2(arr);
if(r1 != r2){
System.out.println("false");
break;
}else{
System.out.println(i +" "+arr.length+" "+r1+" "+r2+" "+" true");
}
}
//System.out.println("true");
}
// 暴力循环
public static int max1(int[] arr){
int max = Integer.MIN_VALUE;
for (int i = 0; i < arr.length; i++) {
for (int j = i; j < arr.length; j++) {
int min = Integer.MAX_VALUE;
int sum = 0;
for (int k = i; k <= j; k++) {
sum += arr[k];
min = Math.min(min, arr[k]);
}
max = Math.max(max, sum * min);
}
}
return max;
}
// 通过单调栈
public static int max2(int[] arr){
int size = arr.length;
int[] sums = new int[size];
sums[0] = arr[0];
// 预处理一个前缀数组和
for (int i = 1; i < arr.length; i++) {
sums[i] = sums[i-1]+arr[i];
}
// 以每一个索引i的数arr[i]作为最小值
int max = Integer.MIN_VALUE;
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < arr.length; i++) {
int leftIndex = 0;
while(!stack.isEmpty() && arr[stack.peek()] >= arr[i]){
int popIndex = stack.pop();
// 此时 arr[popIndex]是数组区间(leftIndex,i)中的最小值
leftIndex = stack.isEmpty() ? -1 : stack.peek();
// 5,1,2,7,6,4,3,8,2,9
int sum = sums[i-1] - (leftIndex==-1 ? 0 : sums[leftIndex]);
max = Math.max(max, sum * arr[popIndex]);
}
stack.push(i);
}
while(!stack.isEmpty()){
int popIndex = stack.pop();
int leftIndex = stack.isEmpty() ? -1 : stack.peek();
int sum = sums[size-1] - (leftIndex==-1 ? 0 : sums[leftIndex]);
max = Math.max(max, sum * arr[popIndex]);
}
return max;
}
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;
}
}