package class26; // 测试链接:https://leetcode.com/problems/sum-of-subarray-minimums/ // subArrayMinSum1是暴力解 // subArrayMinSum2是最优解的思路 // sumSubarrayMins是最优解思路下的单调栈优化 // Leetcode上不要提交subArrayMinSum1、subArrayMinSum2方法,因为没有考虑取摸 // Leetcode上只提交sumSubarrayMins方法,时间复杂度O(N),可以直接通过 public class Code01_SumOfSubarrayMinimums { public static int subArrayMinSum1(int[] arr) { int ans = 0; for (int i = 0; i < arr.length; i++) { for (int j = i; j < arr.length; j++) { int min = arr[i]; for (int k = i + 1; k <= j; k++) { min = Math.min(min, arr[k]); } ans += min; } } return ans; } // 没有用单调栈 public static int subArrayMinSum2(int[] arr) { // left[i] = x : arr[i]左边,离arr[i]最近,<=arr[i],位置在x int[] left = leftNearLessEqual2(arr); // right[i] = y : arr[i]右边,离arr[i]最近,< arr[i],的数,位置在y int[] right = rightNearLess2(arr); int ans = 0; for (int i = 0; i < arr.length; i++) { int start = i - left[i]; int end = right[i] - i; ans += start * end * arr[i]; } return ans; } public static int[] leftNearLessEqual2(int[] arr) { int N = arr.length; int[] left = new int[N]; for (int i = 0; i < N; 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[] rightNearLess2(int[] arr) { int N = arr.length; int[] right = new int[N]; for (int i = 0; i < N; i++) { int ans = N; for (int j = i + 1; j < N; j++) { if (arr[i] > arr[j]) { ans = j; break; } } right[i] = ans; } return right; } public static int sumSubarrayMins(int[] arr) { int[] stack = new int[arr.length]; int[] left = nearLessEqualLeft(arr, stack); int[] right = nearLessRight(arr, stack); long ans = 0; for (int i = 0; i < arr.length; i++) { long start = i - left[i]; long end = right[i] - i; ans += start * end * (long) arr[i]; ans %= 1000000007; } return (int) ans; } public static int[] nearLessEqualLeft(int[] arr, int[] stack) { int N = arr.length; int[] left = new int[N]; int size = 0; for (int i = N - 1; i >= 0; i--) { while (size != 0 && arr[i] <= arr[stack[size - 1]]) { left[stack[--size]] = i; } stack[size++] = i; } while (size != 0) { left[stack[--size]] = -1; } return left; } public static int[] nearLessRight(int[] arr, int[] stack) { int N = arr.length; int[] right = new int[N]; int size = 0; for (int i = 0; i < N; i++) { while (size != 0 && arr[stack[size - 1]] > arr[i]) { right[stack[--size]] = i; } stack[size++] = i; } while (size != 0) { right[stack[--size]] = N; } return right; } public static int[] randomArray(int len, int maxValue) { int[] ans = new int[len]; for (int i = 0; i < len; i++) { ans[i] = (int) (Math.random() * maxValue) + 1; } return ans; } public static void printArray(int[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); } public static void main(String[] args) { int maxLen = 100; int maxValue = 50; int testTime = 100000; System.out.println("测试开始"); for (int i = 0; i < testTime; i++) { int len = (int) (Math.random() * maxLen); int[] arr = randomArray(len, maxValue); int ans1 = subArrayMinSum1(arr); int ans2 = subArrayMinSum2(arr); int ans3 = sumSubarrayMins(arr); if (ans1 != ans2 || ans1 != ans3) { printArray(arr); System.out.println(ans1); System.out.println(ans2); System.out.println(ans3); System.out.println("出错了!"); break; } } System.out.println("测试结束"); } }