2104. Sum of Subarray Ranges

sum = sum(max) - sum(min) -> this is the point!

because nextLarger and prevLarger , prevSmaller, nextSmaller just help us find left bound , right bound

for min, or for max

but we don't know the paired min max how to map to each other (from nextLarger and prevLarger , prevSmaller, nextSmaller

but we need to cal max - min in this subarray's max min pair

seems hard to use range

T: O(n)

S: O(n)

class Solution {
    public long subArrayRanges(int[] nums) {
        int n = nums.length;
        int[] prevSmaller = new int[n];
        int[] nextSmaller = new int[n];
        int[] prevGreater = new int[n];
        int[] nextGreater = new int[n];
        
        Arrays.fill(nextSmaller, n);
        Arrays.fill(prevSmaller, -1);
        Arrays.fill(nextGreater, n);
        Arrays.fill(prevGreater, -1);
        
        Deque<Integer> stack = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && nums[i] < nums[stack.peek()]) {
                nextSmaller[stack.peek()] = i;
                stack.pop();
            }
            stack.push(i);
        }
        
        stack.clear();
        
        for (int i = n-1; i >= 0; i--) {
            while (!stack.isEmpty() && nums[i] <= nums[stack.peek()]) {
                prevSmaller[stack.peek()] = i;
                stack.pop();
            }
            stack.push(i);
        }
        
        stack.clear();
        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && nums[i] > nums[stack.peek()]) {
                nextGreater[stack.peek()] = i;
                stack.pop();
            }
            stack.push(i);
        }
        
        stack.clear();
        
        for (int i = n-1; i >= 0; i--) {
            while (!stack.isEmpty() && nums[i] >= nums[stack.peek()]) {
                prevGreater[stack.peek()] = i;
                stack.pop();
            }
            stack.push(i);
        }
        
        long result = 0L;
        
        // between nextGreater and prevGreater => max
        // between nextSmaller and prevSmaller => min
        // max - min
        for (int i = 0; i < n; i++) {
            result += (long)(nextGreater[i] - i)*(i - prevGreater[i])*nums[i] - (long)(nextSmaller[i] - i)*(i - prevSmaller[i])*nums[i];
        }
        
        return result;
    }
}

/*
range:
the difference between the largest and smallest element in the subarray.
return sum of all in this range

[1,2,3]

[1], range = largest - smallest = 1 - 1 = 0 
[2], range = 2 - 2 = 0
[3], range = 3 - 3 = 0
[1,2], range = 2 - 1 = 1
[2,3], range = 3 - 2 = 1
[1,2,3], range = 3 - 1 = 2
So the sum of all ranges is 0 + 0 + 0 + 1 + 1 + 2 = 4.

if nums[i] is min => the range: prevSmaller: l and nextSmaller; r
nums[i]*(i-l)*(r-i)

if nums[i] is max : b => the range: prevGreater and nextGreater
nums[i]*(i-l)*(r-i)

result += nums[i]*(i-l)*(r-i)
result -= nums[i]*(i-l)*(r-i)


nums[i]*(i-l)*(r-i)
-> 

(i-l)*(r-i)
i็š„ๅทฆ้‚Šๆœ‰ๅนพๅ€‹ๆ•ธ
ๅณ้‚Šๆœ‰ๅนพๅ€‹ๆ•ธ, ็›ธไน˜่ตทไพ†ๅฐฑๆ˜ฏ็ธฝๅ…ฑๅ€‹ๆ•ธ

ex: 1,2,3
max:
nextLarger: [1, 2, 3]
prevLarger: [-1, -1, -1]

็•ถi = 0, nums = 1
(r - i) * (i - l)
(1 - 0) * (0 -(-1)
-> 1*1 = 1

ๅพž้€™่กจไนŸๅฏไปฅ็œ‹ๅ‡บ max 1, ไนŸๅชๆœ‰ไธ€ๆฌก
[1], range = largest - smallest = 1 - 1 = 0 
[2], range = 2 - 2 = 0
[3], range = 3 - 3 = 0
[1,2], range = 2 - 1 = 1
[2,3], range = 3 - 2 = 1
[1,2,3], range = 3 - 1 = 2


่ˆ‰ไพ‹ num = 3ไพ†่ชช, i = 2

nextLarger: [1, 2, 3]
prevLarger: [-1, -1, -1]

(3 - 2) * (2 - (-1))
= 1* 3 = 3
num = 3 ไนŸ็š„็ขบๅ‡บ็พ max 3 ๆฌก (subarray ๅ…งๅ‡บ็พ 3ๆฌก
      i
-1.   2. 3
 
*/

more concise

class Solution {
    public long subArrayRanges(int[] nums) {
        int n = nums.length;
        int[] nextSmaller = new int[n];
        int[] prevSmaller = new int[n];
        int[] nextLarger = new int[n];
        int[] prevLarger = new int[n];
        
        Arrays.fill(nextSmaller, n);
        Arrays.fill(nextLarger, n);
        Arrays.fill(prevSmaller, -1);
        Arrays.fill(prevLarger, -1);
        
        Deque<Integer> stack = new ArrayDeque<>();
        
        // nextSmaller ๏ผš [3,1,2]
        /*
          (then 1 , has nextSmaller , record it! ->nextSmaller[0] = 1 , then pop
        0 (3  
        */
        for (int i = 0; i < n ; i++) {
            while (!stack.isEmpty() && nums[i] < nums[stack.peek()]) {
                nextSmaller[stack.peek()] = i; 
                stack.pop();
            }
            stack.push(i);
        }
        
        stack.clear();
        // prevSmaller, avoid duplicate , we want left one, so when new number == stack number, we keep record it
        for (int i = n-1; i >= 0 ; i--) {
            while (!stack.isEmpty() && nums[i] <= nums[stack.peek()]) {
                prevSmaller[stack.peek()] = i; 
                stack.pop();
            }
            stack.push(i);
        }
        
        stack.clear();
        // nextLarger
        for (int i = 0; i < n ; i++) {
            while (!stack.isEmpty() && nums[i] > nums[stack.peek()]) {
                nextLarger[stack.peek()] = i; 
                stack.pop();
            }
            stack.push(i);
        }
        
        stack.clear();
        // prevLarger, avoid duplicate , we want left one, so when new number == stack number, we keep record it
        for (int i = n-1; i >= 0 ; i--) {
            while (!stack.isEmpty() && nums[i] >= nums[stack.peek()]) {
                prevLarger[stack.peek()] = i; 
                stack.pop();
            }
            stack.push(i);
        }
        
        long result = 0L;
        for (int i = 0; i < n; i++) { // notice the long tupe
            result += (long)nums[i]*(nextLarger[i] - i)*(i - prevLarger[i]) - (long)nums[i]*(nextSmaller[i] - i)*(i - prevSmaller[i]);
        }
        return result;
    }
}

/*
1. brute force
find all subarrays, T: o(n^2), count of subarray -> T: O(n^2), find max, min, -> T: O(n^2*n) -> O(n^3)

2. how to avoid find all subarray

think of each elemnt as the min -> find the left, right bound. it means 
ex: [1,2,3]

1 as min -> [1,2,3] ->with this range, all subarrays' min is 1
...

how to find right bound?
use monostack find
nextSmaller [n, n, n] -> this array we will record each emlent's next smaller [n, n, n]

find left bound
prevSmaller [-1, -1, -1] -> this array we will record each emlent's prev smaller, from end [-1, 0, 1]
(index -> 3's next prev smaller num , index is 1 (nums[1] = 2) )
[n, n, n]
[-1, 0, 1]


for index 0 (1) -> range is -1 to n (ไปฅ num 1 ็‚บ min ็š„index็ฏ„ๅœ) -> [1,2,3] -> in these subarrays (3 subarrays), the min is 1 -> sum(min of these subarrays) => 3*1= 3
-1 0 1 2  n
  [1,2,3]

for index 1 (2) -> range is 0 to n (ไปฅ num 2 ็‚บ min ็š„index็ฏ„ๅœ)-> [2,3] (2 subarrays), min is 2, 2*2=4
   0 1 2  n
  [1,2,3]. range (0 to n) -> ๅฐฑๆ˜ฏ index 1, 2 -> [2, 3]

for index 2 (3) -> range is 1 to n (ไปฅ num 3 ็‚บ min ็š„index็ฏ„ๅœ)-> [3] (1 subarray), min is 3, 3*1 = 3
     1 2  n
  [1,2,3]. range (1 to n) -> ๅฐฑๆ˜ฏ index 2 -> [3]

sum them up -> all min sum = 10

in example,
Explanation: The 6 subarrays of nums are the following:

[1], range = largest - smallest = 1 - 1 = 0 
[2], range = 2 - 2 = 0
[3], range = 3 - 3 = 0
[1,2], range = 2 - 1 = 1
[2,3], range = 3 - 2 = 1
[1,2,3], range = 3 - 1 = 2

-> min: 1 ๅ‡บ็พไบ† 3 ๆฌก, 2 ๅ‡บ็พ 2 ๆฌก, 3 ๅ‡บ็พ 1ๆฌก, ่ทŸๆˆ‘ๅ€‘ๅ‰้ข็š„่จˆ็ฎ—็›ธ็ฌฆ

we can see, actually, the ans is sum(max) - sum(min) -> we don't need to cal diff in each subarray

so we cal the sum(max)

result = sum(max) - sum(min) 


T: O(n)

duplicate case, 
why duplicate case will cause error?
[5,3,3,3,6]
   ^ ^ ^
these 3's range are same , so 3 subarrays are the same

  ๆˆ‘ๅ€‘ๅฏไปฅ็ด„ๅฎšๆœ€ๅณ้‚Š็š„้‡่ค‡ๆ˜ฏๆˆ‘ๅ€‘่ฆ็š„ๆœ€ๅฐๅ€ผ  
   

ๅœจ nextSmaller ๆˆ‘ๅ€‘ไธ็ฎก  [1,3,3,3,2] => index 1's 3 is min the  range is

we handle this in prevSmaller
[]

[1,3,3,3,1]

[-1,-1,-1,-1,-1]

find left bound if smaller or equal -> we find the left bound

for this 3
[1,3,3,3,1]
       ^
     f  -> here we find the left bound

like this
[1,3,3,[3,1]]
     

index 2 3 ->equal!!

index 3 3 -> record prevSmaller[3] = 2 
index 4 1

*/ja



duplicate case

duplicate case, 
why duplicate case will cause error?
[5,3,3,3,6]
   ^ ^ ^
these 3's range are same , so 3 subarrays are the same

  ๆˆ‘ๅ€‘ๅฏไปฅ็ด„ๅฎšๆœ€ๅณ้‚Š็š„้‡่ค‡ๆ˜ฏๆˆ‘ๅ€‘่ฆ็š„ๆœ€ๅฐๅ€ผ  
   
ๆ‰€ไปฅ 3 [8 4 4 8 4]
               ๏ผพ
้€™ๅ€‹ๆœ€ๅณ้‚Š็š„ 4ๆœƒๆ˜ฏๆˆ‘ๅ€‘็š„ right bound
left bound ๅฐฑๅฏไปฅๆœ‰4็š„้‡่ค‡ ๆ‰€ไปฅๅฏไปฅไธ€่ทฏๅˆฐ 8

ไฝ† right bound ๅฐฑไธ่กŒๅ†ๆœ‰้‡่ค‡ไบ†

     3 [8 4 4 8 4] 4                           
                ^
 ๆ‰€ไปฅๅƒ้€™ๆจฃ right bound ๅฐฑๆ˜ฏๅˆฐ ^ ้€™่ฃก
 
 ๆ‰€ไปฅ left bound ๆˆ‘ๅ€‘ๅฏไปฅ <=
 ไฝ† right bound ๆ˜ฏ <
 
 ----------------
 
 ๅ†ๅ›žๅˆฐๅ›žๆœฌ็š„ไพ†็œ‹
 [8 4 4 8 4]
 => ๅฆ‚ๆžœไธ่™•็† ไปฅ 4็‚บminๅŽปๆ‰พๆ™‚, ้€™่ฃกๅฐฑๆœƒๆœ‰ไธ‰ๅ€‹ไธ€ๆจฃ็š„ subarray ้ƒฝๆ˜ฏ [8 4 4 8 4]
 
 ๆ‰€ไปฅ็ด„ๅฎšๆœ€ๅณ้‚Š็š„ 4 ๆ˜ฏๆˆ‘ๅ€‘่ฆ็š„, left bound <=, right bound <
 
 ๆ‰€ไปฅ ็œ‹ index 1 ็š„4ๆ™‚(็ฌฌ1ๅ€‹4)
  [8 4 4 8 4]
  => ๆœƒๆ˜ฏ [8,4]
  
  ็œ‹ index 2 ็š„4ๆ™‚(็ฌฌ2ๅ€‹4)
  [8 4 4 8 4]
  => ๆœƒๆ˜ฏ [4]
  
  ็œ‹ index 3 ็š„4ๆ™‚ (็ฌฌ3ๅ€‹4)
  [8 4 4 8 4]
  => ๆœƒๆ˜ฏ [8 4 4 8 4]
  
  ๅฆ‚ๆญคๅฐฑๅฏไปฅ่งฃๆฑบ้‡่ค‡็š„ๅ•้กŒ๏ผ
 

Last updated