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

📅  最后修改于: 2021-05-17 17:49:22             🧑  作者: Mango

给定一个由N个整数组成的数组arr [] (所有数组元素的完美幂为2 ),任务是计算所有子数组中最大元素的总和。
注意:如果子数组中最大元素的出现频率为偶数,则将该元素的值加到总和的两倍。

例子:

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

  • 初始化一个变量,例如sum ,以存储所需的所有子数组的最大值之和。
  • 生成给定数组arr []的所有可能的子数组。
  • 对于每个生成的子数组,找到最大元素的频率并检查频率是否为偶数。如果发现为真,则将sum2 *最大值。否则,将最大值加到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中包含掩码的所有子数组贡献的值,并维护三个计数器,分别为oddCounteventCountmask的频率。
  • 指针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)