image.png

    题目分析:假设有m个子数组,原问题等价于 m个子数组最大值与最小值之差的累加。怎么求不同子数组的最大值和最小值呢?详见leetcode 907。

    1. class Solution {
    2. public long subArrayRanges(int[] nums) {
    3. int n = nums.length;
    4. long[] min_left = new long[n];
    5. long[] min_right = new long[n];
    6. long[] max_left = new long[n];
    7. long[] max_right = new long[n];
    8. Deque<Integer> min_stack = new LinkedList<>();
    9. Deque<Integer> max_stack = new LinkedList<>();
    10. //1.计算min_left
    11. //从左到右,依次计算nums[i]左侧的第一个不小于nums[i]的数的下标
    12. for(int i = 0; i < n; i++){
    13. while(!min_stack.isEmpty() && nums[min_stack.peek()] >= nums[i]){
    14. min_stack.pop();
    15. }
    16. if(min_stack.isEmpty()){
    17. min_left[i] = -1;
    18. }else{
    19. min_left[i] = min_stack.peek();
    20. }
    21. min_stack.push(i);
    22. }
    23. //2.计算min_right
    24. //从右到左,依次计算nums[i]右侧的第一个大于nums[i]的数的下标
    25. min_stack.clear();
    26. for(int i = n -1; i >= 0; i--){
    27. while(!min_stack.isEmpty() && nums[min_stack.peek()] > nums[i]){
    28. min_stack.pop();
    29. }
    30. if(min_stack.isEmpty()){
    31. min_right[i] = n;
    32. }else{
    33. min_right[i] = min_stack.peek();
    34. }
    35. min_stack.push(i);
    36. }
    37. //3.计算max_left
    38. //从左到右,依次计算nums[i]左侧第一个大于等于nums[i]的数的下标
    39. for(int i = 0; i < n; i++){
    40. while(!max_stack.isEmpty() && nums[max_stack.peek()] <= nums[i]){
    41. max_stack.pop();
    42. }
    43. if(max_stack.isEmpty()){
    44. max_left[i] = -1;
    45. }else{
    46. max_left[i] = max_stack.peek();
    47. }
    48. max_stack.push(i);
    49. }
    50. //4.计算max_right
    51. //从右到左,依次计算nums[i]右侧第一个大于nums[i]的数的下标
    52. max_stack.clear();
    53. for(int i = n -1; i >= 0; i--){
    54. while(!max_stack.isEmpty() && nums[max_stack.peek()] < nums[i]){
    55. max_stack.pop();
    56. }
    57. if(max_stack.isEmpty()){
    58. max_right[i] = n;
    59. }else{
    60. max_right[i] = max_stack.peek();
    61. }
    62. max_stack.push(i);
    63. }
    64. long ans = 0;
    65. for(int i = 0; i < n; i++){
    66. ans += (i - max_left[i]) * (max_right[i] - i) * nums[i];
    67. ans -= (i - min_left[i]) * (min_right[i] - i) * nums[i];
    68. //ans += ((i - max_left[i]) * (max_right[i] - i) - (i - min_left[i]) * (min_right[i] - i)) * nums[i];
    69. }
    70. return ans;
    71. }
    72. }