给定一个由N个整数组成的数组arr [] (所有数组元素的完美幂为2 ),任务是计算所有子数组中最大元素的总和。
注意:如果子数组中最大元素的出现频率为偶数,则将该元素的值加到总和的两倍。
例子:
Input: arr[] = {1, 2}
Output: 5
Explanation: All possible subarrays are {1}, {1, 2}, {2}.
Subarray 1: {1}. Maximum = 1. Sum = 1.
Subarray 2: {1, 2}. Maximum = 2. Sum = 3.
Subarray 3: {2}. Maximum = 2.Sum = 5.
Therefore, required output is 5.
Input: arr[] = {4, 4}
Output: 16
Explanation: All possible subarrays are {4}, {4, 4}, {4}.
Subarray 1: {4}. Maximum = 4. Sum = 1.
Subarray 2: {4, 4}. Maximum = 4. Since the maximum occurs twice in the subarray, Sum = 4 + 8 = 12.
Subarray 3: {4}. Maximum = 4. Sum = 16.
Therefore, required output is 16.
天真的方法:解决此问题的最简单方法是生成给定数组的所有可能的子数组,并在所有子数组中找到最大元素及其出现次数。最后,打印获得的所有最大元素的总和。请按照以下步骤解决问题:
- 初始化一个变量,例如sum ,以存储所需的所有子数组的最大值之和。
- 生成给定数组arr []的所有可能的子数组。
- 对于每个生成的子数组,找到最大元素的频率并检查频率是否为偶数。如果发现为真,则将sum加2 *最大值。否则,将最大值加到sum上。
- 完成上述步骤后,打印sum的值作为结果。
下面是上述方法的实现:
Java
// Java program for the above approach
import java.io.*;
class GFG {
// Function to calculate sum of
// maximum of all subarrays
public static void findSum(int a[])
{
// Stores the sum of maximums
int ans = 0;
// Traverse the array
for (int low = 0;
low < a.length; low++) {
for (int high = low;
high < a.length;
high++) {
// Store the frequency of the
// maximum element in subarray
int count = 0;
int maxNumber = 0;
// Finding maximum
for (int i = low;
i <= high; i++) {
// Increment frequency by 1
if (a[i] == maxNumber)
count++;
// If new maximum is obtained
else if (a[i] > maxNumber) {
maxNumber = a[i];
count = 1;
}
}
// If frequency of maximum
// is even, then add 2*maxNumber.
// Otherwise, add maxNumber
ans += maxNumber
* ((count % 2 == 0) ? 2 : 1);
}
}
// Print the sum obtained
System.out.println(ans);
}
// Driver Code
public static void main(String[] args)
{
int[] arr = { 2, 1, 4, 4, 2 };
// Function Call
findSum(arr);
}
}
C#
// C# program for the above approach
using System;
class GFG {
// Function to calculate sum of
// maximum of all subarrays
public static void findSum(int[] a)
{
// Stores the sum of maximums
int ans = 0;
// Traverse the array
for (int low = 0; low < a.Length; low++) {
for (int high = low; high < a.Length; high++) {
// Store the frequency of the
// maximum element in subarray
int count = 0;
int maxNumber = 0;
// Finding maximum
for (int i = low; i <= high; i++) {
// Increment frequency by 1
if (a[i] == maxNumber)
count++;
// If new maximum is obtained
else if (a[i] > maxNumber) {
maxNumber = a[i];
count = 1;
}
}
// If frequency of maximum
// is even, then add 2*maxNumber.
// Otherwise, add maxNumber
ans += maxNumber
* ((count % 2 == 0) ? 2 : 1);
}
}
// Print the sum obtained
Console.WriteLine(ans);
}
// Driver Code
public static void Main()
{
int[] arr = { 2, 1, 4, 4, 2 };
// Function Call
findSum(arr);
}
}
// This code is contributed by ukasp.
Java
// Java program for the above approach
import java.io.*;
class GFG {
// Function to calculate sum of
// maximum of all subarrays
public static void findSum(int a[])
{
// Calcualte prefix sum array
int[][] prefixSums
= getPrefixSums(a);
// Store the sum of maximums
int ans = 0;
// Traverse the array
for (int low = 0;
low < a.length;
low++) {
for (int high = low;
high < a.length;
high++) {
// Store the frequency of the
// maximum element in subarray
int count = 0;
int maxNumber = 0;
// Store prefix sum of every bit
for (int i = 30; i >= 0; i--) {
// Get the frequency of the
// largest element in subarray
count = getCountLargestNumber(
low, high, i, prefixSums);
if (count > 0) {
maxNumber = (1 << i);
// If frequency of the largest
// element is even, add 2 * maxNumber
// Otherwise, add maxNumber
ans += maxNumber
* ((count % 2 == 0) ? 2 : 1);
break;
}
}
}
}
// Print the required answer
System.out.println(ans);
}
// Function to calcuate the prefix
// sum array
public static int[][] getPrefixSums(
int[] a)
{
// Initialize prefix array
int[][] prefix = new int[32][a.length + 1];
// Start traversing the array
for (int j = 0; j < a.length; j++) {
// Update the prefix array for
// each element in the array
for (int i = 0; i <= 30; i++) {
// To check which bit is set
int mask = (1 << i);
prefix[i][j + 1] += prefix[i][j];
if ((a[j] & mask) > 0)
prefix[i][j + 1]++;
}
}
// Return prefix array
return prefix;
}
// Function to find the maximum
// in subarray {arr[low], ..., arr[high]}
public static int
getCountLargestNumber(
int low, int high, int i,
int[][] prefixSums)
{
return prefixSums[i][high + 1]
- prefixSums[i][low];
}
// Driver Code
public static void main(String[] args)
{
int[] arr = { 2, 1, 4, 4, 2 };
// Function Call
findSum(arr);
}
}
Java
// Java program for the above approach
import java.io.*;
class GFG {
// Function to calculate sum of
// maximum of all subarrays
public static void findSum(int a[])
{
int ans = 0;
int prev = -1;
// Iterate over the range [30, 0]
for (int i = 30; i >= 0; i--) {
int mask = (1 << i);
// Inner loop through the
// length of the array
for (int j = 0;
j < a.length; j++) {
// Divide the array such
// that no subarray will
// have any index set to -1
if (a[j] == -1) {
ans += findSumOfValuesOfRange(
a, prev + 1, j - 1, mask);
prev = j;
}
}
// Find the sum of subarray
ans += findSumOfValuesOfRange(
a, prev + 1, a.length - 1, mask);
}
// Print the sum obtained
System.out.println(ans);
}
// Function that takes any subarray
// S and return values contributed
// by only the subarrays in S containing mask
public static int findSumOfValuesOfRange(
int[] a, int low, int high, int mask)
{
if (low > high)
return 0;
// Stores count even, odd count of
// occurences and maximum element
int evenCount = 0, oddCount = 0,
countLargestNumber = 0;
int prev = low - 1, ans = 0;
// Traverse from low to high
for (int i = low; i <= high; i++) {
// Checking if this position
// in the array is mask
if ((mask & a[i]) > 0) {
// Mask is the largest
// number in subarray.
// Increment count by 1
countLargestNumber++;
// Store parity as 0 or 1
int parity = countLargestNumber % 2;
// Setting a[i]=-1, this
// will help in splitting
// array into subarrays
a[i] = -1;
int count = i - prev;
ans += count;
// Add values contributed
// by those subarrays that
// have an odd frequency
ans += (count - 1)
* ((parity == 1) ? evenCount
: oddCount);
ans += ((parity == 1) ? oddCount
: evenCount);
// Adding values contributed
// by those subarrays that
// have an even frequency
ans += 2 * (count - 1)
* ((parity == 1) ? oddCount
: evenCount);
ans += 2
* ((parity == 1) ? evenCount
: oddCount);
// Set the prev pointer
// to this position
prev = i;
if (parity == 1)
oddCount += count;
else
evenCount += count;
}
}
if (prev != low - 1) {
int count = high - prev;
int parity = countLargestNumber % 2;
ans += count
* ((parity == 1)
? oddCount
: evenCount);
ans += 2 * count
* ((parity == 1)
? evenCount
: oddCount);
ans *= mask;
}
// Return the final sum
return ans;
}
// Driver Code
public static void main(String[] args)
{
int[] arr = { 2, 1, 4, 4, 2 };
// Function call
findSum(arr);
}
}
75
时间复杂度: O(N 3 )
辅助空间: O(1)
优化方法:为了优化上述方法,其思想是存储数组元素每一位的前缀和,并以O(1)计算复杂度找到子数组中最大元素的频率。由于所有数组元素均为2的幂,因此该方法有效。
下面是上述方法的实现:
Java
// Java program for the above approach
import java.io.*;
class GFG {
// Function to calculate sum of
// maximum of all subarrays
public static void findSum(int a[])
{
// Calcualte prefix sum array
int[][] prefixSums
= getPrefixSums(a);
// Store the sum of maximums
int ans = 0;
// Traverse the array
for (int low = 0;
low < a.length;
low++) {
for (int high = low;
high < a.length;
high++) {
// Store the frequency of the
// maximum element in subarray
int count = 0;
int maxNumber = 0;
// Store prefix sum of every bit
for (int i = 30; i >= 0; i--) {
// Get the frequency of the
// largest element in subarray
count = getCountLargestNumber(
low, high, i, prefixSums);
if (count > 0) {
maxNumber = (1 << i);
// If frequency of the largest
// element is even, add 2 * maxNumber
// Otherwise, add maxNumber
ans += maxNumber
* ((count % 2 == 0) ? 2 : 1);
break;
}
}
}
}
// Print the required answer
System.out.println(ans);
}
// Function to calcuate the prefix
// sum array
public static int[][] getPrefixSums(
int[] a)
{
// Initialize prefix array
int[][] prefix = new int[32][a.length + 1];
// Start traversing the array
for (int j = 0; j < a.length; j++) {
// Update the prefix array for
// each element in the array
for (int i = 0; i <= 30; i++) {
// To check which bit is set
int mask = (1 << i);
prefix[i][j + 1] += prefix[i][j];
if ((a[j] & mask) > 0)
prefix[i][j + 1]++;
}
}
// Return prefix array
return prefix;
}
// Function to find the maximum
// in subarray {arr[low], ..., arr[high]}
public static int
getCountLargestNumber(
int low, int high, int i,
int[][] prefixSums)
{
return prefixSums[i][high + 1]
- prefixSums[i][low];
}
// Driver Code
public static void main(String[] args)
{
int[] arr = { 2, 1, 4, 4, 2 };
// Function Call
findSum(arr);
}
}
75
时间复杂度: O(N 2 )
辅助空间: O(32 * N)
高效方法:为了优化上述方法,其思想是使用所有数组元素均为2的幂的属性,并利用该属性来解决问题。请按照以下步骤解决问题:
- 以降序遍历2的所有幂。考虑2的任意幂作为掩码。
- 将数组划分为子数组,以使任何子数组都不会包含arr [index] = -1 ,其中索引是数组中的任何有效位置。
- 令从上述步骤获得的子数组为S。遍历S并从外部循环中添加仅由S中具有当前掩码的子数组贡献的值。还要将arr [index] = mask的相应位置设置为arr [index] = -1 。
- 要计算S中包含掩码的所有子数组贡献的值,并维护三个计数器,分别为oddCount , eventCount和mask的频率。
- 指针prev指向上一个索引,因此arr [prev] = mask 。
- 在任何索引处,其中arr [index] = mask ,可以通过从索引中减去prev来获取掩码的最后一次出现与当前出现之间的整数计数。使用此计数和掩码频率的奇偶校验,使用公式count =(index – prev)来获取包含掩码的所有连续子数组贡献的值,并将该计数添加到答案中。
- 如果最大频率为偶数或奇数,并且奇偶校验为奇数:
- 由掩码频率为奇数的所有连续子数组贡献的值是(count – 1)* evenCount +奇数。
- 由所有连续的子数组贡献的值,它们的掩码频率为偶数为2 *(count – 1)* oddCount + 2 * evenCount 。
- 否则,如果奇偶校验是偶数:
- 由掩码频率为奇数的所有连续子数组贡献的值是(count – 1)* oddCount + evenCount 。
- 所有掩码频率为偶数的连续子数组贡献的值是2 *(count – 1)* evenCount + 2 *奇数。
- 将所有相应的值添加到答案中。如果奇偶校验为偶数,也将计数添加到evenCount。否则,将count添加到oddCount 。
下面是上述方法的实现:
Java
// Java program for the above approach
import java.io.*;
class GFG {
// Function to calculate sum of
// maximum of all subarrays
public static void findSum(int a[])
{
int ans = 0;
int prev = -1;
// Iterate over the range [30, 0]
for (int i = 30; i >= 0; i--) {
int mask = (1 << i);
// Inner loop through the
// length of the array
for (int j = 0;
j < a.length; j++) {
// Divide the array such
// that no subarray will
// have any index set to -1
if (a[j] == -1) {
ans += findSumOfValuesOfRange(
a, prev + 1, j - 1, mask);
prev = j;
}
}
// Find the sum of subarray
ans += findSumOfValuesOfRange(
a, prev + 1, a.length - 1, mask);
}
// Print the sum obtained
System.out.println(ans);
}
// Function that takes any subarray
// S and return values contributed
// by only the subarrays in S containing mask
public static int findSumOfValuesOfRange(
int[] a, int low, int high, int mask)
{
if (low > high)
return 0;
// Stores count even, odd count of
// occurences and maximum element
int evenCount = 0, oddCount = 0,
countLargestNumber = 0;
int prev = low - 1, ans = 0;
// Traverse from low to high
for (int i = low; i <= high; i++) {
// Checking if this position
// in the array is mask
if ((mask & a[i]) > 0) {
// Mask is the largest
// number in subarray.
// Increment count by 1
countLargestNumber++;
// Store parity as 0 or 1
int parity = countLargestNumber % 2;
// Setting a[i]=-1, this
// will help in splitting
// array into subarrays
a[i] = -1;
int count = i - prev;
ans += count;
// Add values contributed
// by those subarrays that
// have an odd frequency
ans += (count - 1)
* ((parity == 1) ? evenCount
: oddCount);
ans += ((parity == 1) ? oddCount
: evenCount);
// Adding values contributed
// by those subarrays that
// have an even frequency
ans += 2 * (count - 1)
* ((parity == 1) ? oddCount
: evenCount);
ans += 2
* ((parity == 1) ? evenCount
: oddCount);
// Set the prev pointer
// to this position
prev = i;
if (parity == 1)
oddCount += count;
else
evenCount += count;
}
}
if (prev != low - 1) {
int count = high - prev;
int parity = countLargestNumber % 2;
ans += count
* ((parity == 1)
? oddCount
: evenCount);
ans += 2 * count
* ((parity == 1)
? evenCount
: oddCount);
ans *= mask;
}
// Return the final sum
return ans;
}
// Driver Code
public static void main(String[] args)
{
int[] arr = { 2, 1, 4, 4, 2 };
// Function call
findSum(arr);
}
}
75
时间复杂度: O(30 * N)
辅助空间: O(1)