给定长度为N的数组arr [],任务是找到该数组每个可能子数组的最大元素之和。
例子:
Input : arr[] = {1, 3, 1, 7}
Output : 42
Max of all sub-arrays:
{1} - 1
{1, 3} - 3
{1, 3, 1} - 3
{1, 3, 1, 7} - 7
{3} - 3
{3, 1} - 3
{3, 1, 7} - 7
{1} - 1
{1, 7} - 7
{7} - 7
1 + 3 + 3 + 7 + 3 + 3 + 7 + 1 + 7 + 7 = 42
Input : arr[] = {1, 1, 1, 1, 1}
Output : 15
我们已经在本文中讨论了使用堆栈的O(N)方法。
方法 :
在本文中,我们将学习如何使用分而治之解决此问题。
假设第i个索引的元素最大。对于任何包含索引“ i”的子数组,“ i”处的元素在子数组中始终为最大。
如果第i个索引的元素最大,则可以肯定地说,第(i + 1)*(Ni)个子数组中第i个元素的索引最大。因此,其总贡献为arr [i] *(i + 1)*(Ni)。现在,我们将数组分为两部分,(0,i-1)和(i + 1,N-1),并将相同的算法分别应用于这两个部分。
因此,我们的一般递归关系将是:
maxSumSubarray(arr, l, r) = arr[i]*(r-i+1)*(i-l+1)
+ maxSumSubarray(arr, l, i-1)
+ maxSumSubarray(arr, i+1, r)
where i is index of maximum element in range [l, r].
现在,我们需要一种有效地回答rangeMax()查询的方法。段树将是回答此查询的有效方法。我们最多需要回答N次此查询。因此,我们的分治法算法的时间复杂度将为O(Nlog(N))。
如果我们必须回答“所有子数组的总数之和”的问题,那么我们将使用段树来回答rangeMin()查询。为此,您可以浏览文章细分树的最小范围。
下面是实现代码:
C++
// C++ implementation of the above approach
#include
#define seg_max 51
using namespace std;
// Array to store segment tree.
// In first we will store the maximum
// of a range
// In second, we will store index of
// that range
pair seg_tree[seg_max];
// Size of array declared global
// to maintain simplicity in code
int n;
// Function to build segment tree
pair buildMaxTree(int l, int r, int i, int arr[])
{
// Base case
if (l == r) {
seg_tree[i] = { arr[l], l };
return seg_tree[i];
}
// Finding the maximum among left and right child
seg_tree[i] = max(buildMaxTree(l, (l + r) / 2, 2 * i + 1, arr),
buildMaxTree((l + r) / 2 + 1, r, 2 * i + 2, arr));
// Returning the maximum to parent
return seg_tree[i];
}
// Function to perform range-max query in segment tree
pair rangeMax(int l, int r, int arr[],
int i = 0, int sl = 0, int sr = n - 1)
{
// Base cases
if (sr < l || sl > r)
return { INT_MIN, -1 };
if (sl >= l and sr <= r)
return seg_tree[i];
// Finding the maximum among left and right child
return max(rangeMax(l, r, arr, 2 * i + 1, sl, (sl + sr) / 2),
rangeMax(l, r, arr, 2 * i + 2, (sl + sr) / 2 + 1, sr));
}
// Function to find maximum sum subarray
int maxSumSubarray(int arr[], int l = 0, int r = n - 1)
{
// base case
if (l > r)
return 0;
// range-max query to determine
// largest in the range.
pair a = rangeMax(l, r, arr);
// divide the array in two parts
return a.first * (r - a.second + 1) * (a.second - l + 1)
+ maxSumSubarray(arr, l, a.second - 1)
+ maxSumSubarray(arr, a.second + 1, r);
}
// Driver Code
int main()
{
// Input array
int arr[] = { 1, 3, 1, 7 };
// Size of array
n = sizeof(arr) / sizeof(int);
// Builind the segment-tree
buildMaxTree(0, n - 1, 0, arr);
cout << maxSumSubarray(arr);
return 0;
}
Java
// Java implementation of the above approach
class GFG {
static class pair {
int first, second;
public pair(int first, int second) {
this.first = first;
this.second = second;
}
}
static final int seg_max = 51;
// Array to store segment tree.
// In first we will store the maximum
// of a range
// In second, we will store index of
// that range
static pair[] seg_tree = new pair[seg_max];
// Size of array declared global
// to maintain simplicity in code
static int n;
// Function to build segment tree
static pair buildMaxTree(int l, int r, int i, int arr[])
{
// Base case
if (l == r) {
seg_tree[i] = new pair(arr[l], l);
return seg_tree[i];
}
// Finding the maximum among left and right child
seg_tree[i] = max(buildMaxTree(l, (l + r) / 2, 2 * i + 1, arr),
buildMaxTree((l + r) / 2 + 1, r, 2 * i + 2, arr));
// Returning the maximum to parent
return seg_tree[i];
}
// Function to perform range-max query in segment tree
static pair rangeMax(int l, int r, int arr[],
int i, int sl, int sr)
{
// Base cases
if (sr < l || sl > r)
return new pair(Integer.MIN_VALUE, -1);
if (sl >= l && sr <= r)
return seg_tree[i];
// Finding the maximum among left and right child
return max(rangeMax(l, r, arr, 2 * i + 1, sl, (sl + sr) / 2),
rangeMax(l, r, arr, 2 * i + 2, (sl + sr) / 2 + 1, sr));
}
static pair max(pair f, pair s) {
if (f.first > s.first)
return f;
else
return s;
}
// Function to find maximum sum subarray
static int maxSumSubarray(int arr[], int l, int r)
{
// base case
if (l > r)
return 0;
// range-max query to determine
// largest in the range.
pair a = rangeMax(l, r, arr, 0, 0, n - 1);
// divide the array in two parts
return a.first * (r - a.second + 1) * (a.second - l + 1)
+ maxSumSubarray(arr, l, a.second - 1)
+ maxSumSubarray(arr, a.second + 1, r);
}
// Driver Code
public static void main(String[] args)
{
// Input array
int arr[] = { 1, 3, 1, 7 };
// Size of array
n = arr.length;
// Builind the segment-tree
buildMaxTree(0, n - 1, 0, arr);
System.out.print(maxSumSubarray(arr, 0, n - 1));
}
}
// This code is contributed by 29AjayKumar
C#
// C# implementation of the above approach
using System;
class GFG {
class pair {
public int first, second;
public pair(int first, int second) {
this.first = first;
this.second = second;
}
}
static readonly int seg_max = 51;
// Array to store segment tree.
// In first we will store the maximum
// of a range
// In second, we will store index of
// that range
static pair[] seg_tree = new pair[seg_max];
// Size of array declared global
// to maintain simplicity in code
static int n;
// Function to build segment tree
static pair buildMaxTree(int l, int r, int i, int []arr)
{
// Base case
if (l == r) {
seg_tree[i] = new pair(arr[l], l);
return seg_tree[i];
}
// Finding the maximum among left and right child
seg_tree[i] = max(buildMaxTree(l, (l + r) / 2, 2 * i + 1, arr),
buildMaxTree((l + r) / 2 + 1, r, 2 * i + 2, arr));
// Returning the maximum to parent
return seg_tree[i];
}
// Function to perform range-max query in segment tree
static pair rangeMax(int l, int r, int []arr,
int i, int sl, int sr)
{
// Base cases
if (sr < l || sl > r)
return new pair(int.MinValue, -1);
if (sl >= l && sr <= r)
return seg_tree[i];
// Finding the maximum among left and right child
return max(rangeMax(l, r, arr, 2 * i + 1, sl, (sl + sr) / 2),
rangeMax(l, r, arr, 2 * i + 2, (sl + sr) / 2 + 1, sr));
}
static pair max(pair f, pair s) {
if (f.first > s.first)
return f;
else
return s;
}
// Function to find maximum sum subarray
static int maxSumSubarray(int []arr, int l, int r)
{
// base case
if (l > r)
return 0;
// range-max query to determine
// largest in the range.
pair a = rangeMax(l, r, arr, 0, 0, n - 1);
// divide the array in two parts
return a.first * (r - a.second + 1) * (a.second - l + 1)
+ maxSumSubarray(arr, l, a.second - 1)
+ maxSumSubarray(arr, a.second + 1, r);
}
// Driver Code
public static void Main(String[] args)
{
// Input array
int []arr = { 1, 3, 1, 7 };
// Size of array
n = arr.Length;
// Builind the segment-tree
buildMaxTree(0, n - 1, 0, arr);
Console.Write(maxSumSubarray(arr, 0, n - 1));
}
}
// This code is contributed by PrinciRaj1992
输出:
42
时间复杂度:O(Nlog(N))