给定一个数组arr [] ,任务是找到该数组的每个可能子数组的最大元素之和。
例子:
Input: arr[] = {1, 3, 2}
Output: 15
All possible sub-arrays are {1}, {2}, {3}, {1, 3}, {3, 2} and {1, 3, 2}
And, the sum of all the maximum elements is 1 + 2 + 3 + 3 + 3 + 3 = 15
Input: arr[] = {3, 1}
Output: 7
一种简单的方法是生成所有子数组,然后将所有子数组中的最大元素求和。该解决方案的时间复杂度将为O(n 3 )。
更好的方法:
优化的关键是问题-
In how many segments, the value at an index will be maximum?
我们可能想到的下一个想法是针对数组arr中的每个索引i ,我们尝试找到:
左数:我们向索引i的左侧进行迭代,直到没有遇到严格大于arr [i]的元素,或者没有到达数组的左端。让我们将给定数组的索引i的此计数称为CLi 。
正确的计数:我们朝索引的右边进行迭代,直到没有遇到大于或等于索引值的元素,或者没有到达正确的末端。让我们将给定数组的索引i的此计数称为CRi 。
(CLi + 1)*(CRi + 1)将是当前索引i的子数组数量,其值将为最大值,因为有CLi + 1种从左侧选择元素的方式(包括不选择任何元素)和CRi + 1从右侧选择元素的方法。
The time complexity of this approach will be O(n2)
最佳方法:
使用O(n)时间的堆栈数据结构可以解决此问题。这个想法与以前的方法相同。为了节省时间,我们将使用C++标准模板库中的堆栈。
剩余计数:让CLi代表索引i的剩余计数。索引i的CLi可以定义为索引i和最右边的元素之间的元素数量,这些元素的值严格大于arr [i]且索引小于i 。如果没有这样的元素,则元素的CLi等于索引i左侧的元素数。
为此,我们将只从左到右插入元素的索引到堆栈中。让我们假设,我们正在堆栈中插入索引i ,而j是堆栈中当前存在的最顶层元素的索引。当值arr [i]大于或等于堆栈中最顶层索引的值并且堆栈不为空时,请继续弹出堆栈中的元素。每当弹出元素时,当前索引(i)的左计数(CLi)都会更新为CLi = CLi + CLj + 1 。
正确计数:我们以类似方式计算所有索引的正确计数。唯一的区别是我们在数组中从右到左遍历时将元素推入堆栈。尽管arr [i]严格大于堆栈中最顶部索引的值,并且堆栈不为空,但请继续弹出元素。每当弹出一个元素时,当前索引(i)的正确计数就会更新为CRi = CRi + CRj + 1 。
最后一步:让ans为包含最终答案的变量。我们将其初始化为0 。然后,我们将通过所有的索引进行迭代从1到所述阵列的n和从1更新ANS为ANS = ANS +(CLI + 1)*(CRI + 1)* ARR [I]对于i的所有可能值以n 。
下面是上述方法的实现:
C++
// C++ implementation of the approach
#include
#include
using namespace std;
// Function to return the required sum
int findMaxSum(int arr[], int n)
{
// Arrays for maintaining left and right count
int CL[n] = { 0 }, CR[n] = { 0 };
// Stack for storing the indexes
stack q;
// Calculate left count for every index
for (int i = 0; i < n; i++) {
while (q.size() != 0 && arr[q.top()] <= arr[i]) {
CL[i] += CL[q.top()] + 1;
q.pop();
}
q.push(i);
}
// Clear the stack
while (q.size() != 0)
q.pop();
// Calculate right count for every index
for (int i = n - 1; i >= 0; i--) {
while (q.size() != 0 && arr[q.top()] < arr[i]) {
CR[i] += CR[q.top()] + 1;
q.pop();
}
q.push(i);
}
// Clear the stack
while (q.size() != 0)
q.pop();
// To store the required sum
int ans = 0;
// Calculate the final sum
for (int i = 0; i < n; i++)
ans += (CL[i] + 1) * (CR[i] + 1) * arr[i];
return ans;
}
// Driver code
int main()
{
int arr[] = { 1, 3, 2 };
int n = sizeof(arr) / sizeof(arr[0]);
cout << findMaxSum(arr, n);
}
Java
// Java implementation of the above approach
import java.util.*;
public class GFG
{
// Function to return the required sum
static int findMaxSum(int arr[], int n)
{
// Arrays for maintaining left and right count
int CL[] = new int[n], CR[] = new int[n];
// Stack for storing the indexes
Stack q = new Stack();
// Calculate left count for every index
for (int i = 0; i < n; i++)
{
while (q.size() != 0 && arr[q.peek()] <= arr[i])
{
CL[i] += CL[q.peek()] + 1;
q.pop();
}
q.push(i);
}
// Clear the stack
while (q.size() != 0)
q.pop();
// Calculate right count for every index
for (int i = n - 1; i >= 0; i--)
{
while (q.size() != 0 && arr[q.peek()] < arr[i])
{
CR[i] += CR[q.peek()] + 1;
q.pop();
}
q.push(i);
}
// Clear the stack
while (q.size() != 0)
q.pop();
// To store the required sum
int ans = 0;
// Calculate the final sum
for (int i = 0; i < n; i++)
ans += (CL[i] + 1) * (CR[i] + 1) * arr[i];
return ans;
}
// Driver code
public static void main(String[] args)
{
int arr[] = { 1, 3, 2 };
int n = arr.length;
System.out.println(findMaxSum(arr, n));
}
}
// This code is contributed by Rituraj Jain
Python3
# Python3 implementation of the approach
# Function to return the required sum
def findMinSum(arr, n):
# Arrays for maintaining left
# and right count
CL = [0] * n
CR = [0] * n
# Stack for storing the indexes
q = []
# Calculate left count for every index
for i in range(0, n):
while (len(q) != 0 and
arr[q[-1]] <= arr[i]):
CL[i] += CL[q[-1]] + 1
q.pop()
q.append(i)
# Clear the stack
while len(q) != 0:
q.pop()
# Calculate right count for every index
for i in range(n - 1, -1, -1):
while (len(q) != 0 and
arr[q[-1]] < arr[i]):
CR[i] += CR[q[-1]] + 1
q.pop()
q.append(i)
# Clear the stack
while len(q) != 0:
q.pop()
# To store the required sum
ans = 0
# Calculate the final sum
for i in range(0, n):
ans += (CL[i] + 1) * (CR[i] + 1) * arr[i]
return ans
# Driver code
if __name__ == "__main__":
arr = [1, 3, 2]
n = len(arr)
print(findMinSum(arr, n))
# This code is contributed by Rituraj Jain
C#
// C# implementation of the above approach
using System;
using System.Collections.Generic;
class GFG
{
// Function to return the required sum
static int findMaxSum(int []arr, int n)
{
// Arrays for maintaining left and right count
int []CL = new int[n]; int []CR = new int[n];
// Stack for storing the indexes
Stack q = new Stack();
// Calculate left count for every index
for (int i = 0; i < n; i++)
{
while (q.Count != 0 && arr[q.Peek()] <= arr[i])
{
CL[i] += CL[q.Peek()] + 1;
q.Pop();
}
q.Push(i);
}
// Clear the stack
while (q.Count != 0)
q.Pop();
// Calculate right count for every index
for (int i = n - 1; i >= 0; i--)
{
while (q.Count != 0 && arr[q.Peek()] < arr[i])
{
CR[i] += CR[q.Peek()] + 1;
q.Pop();
}
q.Push(i);
}
// Clear the stack
while (q.Count != 0)
q.Pop();
// To store the required sum
int ans = 0;
// Calculate the final sum
for (int i = 0; i < n; i++)
ans += (CL[i] + 1) * (CR[i] + 1) * arr[i];
return ans;
}
// Driver code
public static void Main(String[] args)
{
int []arr = { 1, 3, 2 };
int n = arr.Length;
Console.WriteLine(findMaxSum(arr, n));
}
}
// This code has been contributed by 29AjayKumar
15
时间复杂度: O(n)