📌  相关文章
📜  通过将偶数频繁最大值相加两次来计算所有子数组的最大值之和

📅  最后修改于: 2021-09-07 05:17:46             🧑  作者: Mango

给定一个由N 个整数组成的数组arr[] (所有数组元素都是2完美幂),任务是计算所有子数组中最大元素的总和。

注意:如果子数组中最大元素的频率为偶数,则将该元素值的两倍加到总和中。

例子:

朴素的方法:解决这个问题的最简单的方法是生成给定数组的所有可能的子数组,并找到所有子数组中的最大元素以及它们出现的次数。最后,打印获得的所有最大元素的总和。请按照以下步骤解决问题:

  • 初始化一个变量,比如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中包含掩码的所有子数组贡献的值,并维护三个计数器: oddCounteventCountmask的频率。
  • 指针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