📌  相关文章
📜  所有子数组的最小元素的总和

📅  最后修改于: 2021-04-21 23:28:16             🧑  作者: Mango

给定一个n个整数的数组A。任务是找到A的所有可能(连续)子数组的最小值之和。

例子:

方法:朴素的方法是生成所有可能的(连续的)子数组,找到它们的最小值并将它们添加到结果中。时间复杂度将为O(N 2 )。

高效方法:解决该问题的一般直觉是找到sum(A [i] * f(i)) ,其中f(i)是其中A [i]为最小值的子数组的数量。

为了找到f [i] ,我们需要找出:
left [i]A [i]左边严格大于数字的长度,
right [i]A [i]右边较大数字的长度。

我们创建两个数组left []和right [],使得:
left [i] + 1等于以A [i]结尾的子数组的数量,并且A [i]仅是一个最小值。
类似地, right [i] + 1等于以A [i]开头的子数组的数量,并且A [i]是第一个最小值。

最后, f(i)=(left [i])*(right [i]) ,其中f [i]等于A [i]最小的子数组的总数。

下面是上述方法的实现

C++
// CPP implementation of above approach
#include 
using namespace std;
  
// Function to return required minimum sum
int sumSubarrayMins(int A[], int n)
{
    int left[n], right[n];
  
    stack > s1, s2;
  
    // getting number of element strictly larger 
    // than A[i] on Left.
    for (int i = 0; i < n; ++i) {
        int cnt = 1;
  
        // get elements from stack until element 
        // greater than A[i] found
        while (!s1.empty() && (s1.top().first) > A[i]) {
            cnt += s1.top().second;
            s1.pop();
        }
  
        s1.push({ A[i], cnt });
        left[i] = cnt;
    }
  
    // getting number of element larger than A[i] on Right.
    for (int i = n - 1; i >= 0; --i) {
        int cnt = 1;
  
        // get elements from stack until element greater
        // or equal to A[i] found
        while (!s2.empty() && (s2.top().first) >= A[i]) {
            cnt += s2.top().second;
            s2.pop();
        }
  
        s2.push({ A[i], cnt });
        right[i] = cnt;
    }
  
    int result = 0;
  
    // calculating required resultult
    for (int i = 0; i < n; ++i)
        result = (result + A[i] * left[i] * right[i]);
  
    return result;
}
  
// Driver program
int main()
{
    int A[] = { 3, 1, 2, 4 };
  
    int n = sizeof(A) / sizeof(A[0]);
  
    // function call to get required resultult
    cout << sumSubarrayMins(A, n);
  
    return 0;
}
// This code is written by Sanjit_Prasad


Java
// Java implementation of above approach
import java.util.*;
  
class GFG 
{
static class pair 
{ 
    int first, second; 
    public pair(int first, int second) 
    { 
        this.first = first; 
        this.second = second; 
    } 
}
  
// Function to return required minimum sum
static int sumSubarrayMins(int A[], int n)
{
    int []left = new int[n];
    int []right = new int[n];
  
    Stack s1 = new Stack();
    Stack s2 = new Stack();
      
    // getting number of element strictly larger 
    // than A[i] on Left.
    for (int i = 0; i < n; ++i) 
    {
        int cnt = 1;
  
        // get elements from stack until element 
        // greater than A[i] found
        while (!s1.isEmpty() && 
               (s1.peek().first) > A[i])
        {
            cnt += s1.peek().second;
            s1.pop();
        }
  
        s1.push(new pair(A[i], cnt));
        left[i] = cnt;
    }
  
    // getting number of element larger 
    // than A[i] on Right.
    for (int i = n - 1; i >= 0; --i) 
    {
        int cnt = 1;
  
        // get elements from stack until element 
        // greater or equal to A[i] found
        while (!s2.isEmpty() && 
               (s2.peek().first) >= A[i]) 
        {
            cnt += s2.peek().second;
            s2.pop();
        }
  
        s2.push(new pair(A[i], cnt));
        right[i] = cnt;
    }
  
    int result = 0;
  
    // calculating required resultult
    for (int i = 0; i < n; ++i)
        result = (result + A[i] * left[i] * 
                                  right[i]);
  
    return result;
}
  
// Driver Code
public static void main(String[] args) 
{
    int A[] = { 3, 1, 2, 4 };
  
    int n = A.length;
  
    // function call to get required result
    System.out.println(sumSubarrayMins(A, n));
}
}
  
// This code is contributed by PrinciRaj1992


Python3
# Python3 implementation of above approach 
  
# Function to return required minimum sum 
def sumSubarrayMins(A, n): 
  
    left, right = [None] * n, [None] * n 
      
    # Use list as stack
    s1, s2 = [], [] 
  
    # getting number of element strictly 
    # larger than A[i] on Left. 
    for i in range(0, n): 
        cnt = 1
  
        # get elements from stack until 
        # element greater than A[i] found 
        while len(s1) > 0 and s1[-1][0] > A[i]: 
            cnt += s1[-1][1] 
            s1.pop() 
  
        s1.append([A[i], cnt]) 
        left[i] = cnt 
  
    # getting number of element
    # larger than A[i] on Right. 
    for i in range(n - 1, -1, -1): 
        cnt = 1
  
        # get elements from stack until 
        # element greater or equal to A[i] found 
        while len(s2) > 0 and s2[-1][0] >= A[i]: 
            cnt += s2[-1][1] 
            s2.pop() 
  
        s2.append([A[i], cnt]) 
        right[i] = cnt 
  
    result = 0
  
    # calculating required resultult 
    for i in range(0, n): 
        result += A[i] * left[i] * right[i] 
  
    return result 
  
# Driver Code
if __name__ == "__main__":
  
    A = [3, 1, 2, 4]
    n = len(A) 
  
    # function call to get 
    # required resultult 
    print(sumSubarrayMins(A, n)) 
  
# This code is contributed
# by Rituraj Jain


C#
// C# implementation of above approach
using System;
using System.Collections.Generic;
  
class GFG 
{
public class pair 
{ 
    public int first, second; 
    public pair(int first, int second) 
    { 
        this.first = first; 
        this.second = second; 
    } 
}
  
// Function to return required minimum sum
static int sumSubarrayMins(int []A, int n)
{
    int []left = new int[n];
    int []right = new int[n];
  
    Stack s1 = new Stack();
    Stack s2 = new Stack();
      
    // getting number of element strictly larger 
    // than A[i] on Left.
    for (int i = 0; i < n; ++i) 
    {
        int cnt = 1;
  
        // get elements from stack until element 
        // greater than A[i] found
        while (s1.Count!=0 && 
            (s1.Peek().first) > A[i])
        {
            cnt += s1.Peek().second;
            s1.Pop();
        }
  
        s1.Push(new pair(A[i], cnt));
        left[i] = cnt;
    }
  
    // getting number of element larger 
    // than A[i] on Right.
    for (int i = n - 1; i >= 0; --i) 
    {
        int cnt = 1;
  
        // get elements from stack until element 
        // greater or equal to A[i] found
        while (s2.Count != 0 && 
              (s2.Peek().first) >= A[i]) 
        {
            cnt += s2.Peek().second;
            s2.Pop();
        }
  
        s2.Push(new pair(A[i], cnt));
        right[i] = cnt;
    }
  
    int result = 0;
  
    // calculating required resultult
    for (int i = 0; i < n; ++i)
        result = (result + A[i] * left[i] * 
                                  right[i]);
  
    return result;
}
  
// Driver Code
public static void Main(String[] args) 
{
    int []A = { 3, 1, 2, 4 };
  
    int n = A.Length;
  
    // function call to get required result
    Console.WriteLine(sumSubarrayMins(A, n));
}
}
  
// This code is contributed by Rajput-Ji


输出:
17

时间复杂度: O(N),其中N是A的长度。
空间复杂度: O(N)。