给定一个由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[] 的所有可能的子数组。
- 对于每个生成的子数组,找出最大元素的频率并检查频率是否为偶数。如果发现为真,则将2 * 最大值添加到sum 。否则,将最大值添加到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);
}
}
Python3
# Python3 program for the above approach
# Function to calculate sum of
# maximum of all subarrays
def findSum(a):
# Stores the sum of maximums
ans = 0
# Traverse the array
for low in range(0, len(a)):
for high in range(low,len(a)):
# Store the frequency of the
# maximum element in subarray
count = 0
maxNumber = 0
# Finding maximum
for i in range(low, high + 1):
# Increment frequency by 1
if (a[i] == maxNumber):
count += 1
# If new maximum is obtained
elif (a[i] > maxNumber):
maxNumber = a[i]
count = 1
# If frequency of maximum
# is even, then add 2*maxNumber.
# Otherwise, add maxNumber
if count % 2:
ans += maxNumber
else:
ans += maxNumber * 2
# Print the sum obtained
print(ans)
# Driver Code
arr = [ 2, 1, 4, 4, 2 ]
# Function Call
findSum(arr)
# This code is contributed by rohitsingh07052
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[])
{
// Calculate 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 calculate 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
// occurrences 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[])
{
// Calculate 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 calculate 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来获取掩码的最后一次出现和当前出现之间的整数计数。使用此计数和掩码频率的奇偶校验,获取包含掩码的所有连续子数组贡献的值,使用公式计数 = (index – prev)并将计数添加到答案中。
- 如果最大值的频率是偶数或奇数并且奇偶校验是奇数:
- 掩码频率为奇数的所有连续子数组贡献的值是(count – 1)*evenCount +oddCount 。
- 掩码频率为偶数的所有连续子数组贡献的值是2*(count – 1)*oddCount + 2*evenCount 。
- 否则,如果奇偶校验为偶数:
- 掩码频率为奇数的所有连续子数组贡献的值是(count – 1)*oddCount + evenCount 。
- 掩码频率为偶数的所有连续子数组贡献的值是2*(count – 1) * evenCount + 2 *oddCount 。
- 将所有相应的值添加到答案中。如果奇偶校验为偶数,还要将计数添加到 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
// occurrences 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)
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live