给定一个n个整数的数组A。任务是找到A的所有可能(连续)子数组的最小值之和。
例子:
Input: A = [3, 1, 2, 4]
Output: 17
Explanation: Subarrays are [3], [1], [2], [4], [3, 1], [1, 2], [2, 4], [3, 1, 2], [1, 2, 4], [3, 1, 2, 4].
Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1. Sum is 17.
Input : A = [1, 2, 3, 4]
Output : 20
方法:朴素的方法是生成所有可能的(连续的)子数组,找到它们的最小值并将它们添加到结果中。时间复杂度将为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)。