📌  相关文章
📜  两个连续子数组之和之间的最大绝对差

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

给定一个整数数组,找出两个不重叠的连续子数组,使得两个子数组之和的绝对差最大。

例子:

Input: [-2, -3, 4, -1, -2, 1, 5, -3]
Output: 12
Two subarrays are [-2, -3] and [4, -1, -2, 1, 5]

Input: [2, -1, -2, 1, -4, 2, 8]
Output: 16
Two subarrays are [-1, -2, 1, -4] and [2, 8] 

预期时间复杂度为 O(n)。

这个想法是对于给定数组 arr[0…n-1] 中的每个索引 i,计算位于子数组 arr[0…i] 和 arr[i+1 …n-1] 中的最大和最小和子数组。我们维护了四个数组,它们在子数组 arr[0…i] 和 arr[i+1 … n-1] 中存储数组中每个索引 i 的最大和最小和。

leftMax[] : An element leftMax[i] of this 
            array stores the maximum value 
            in subarray arr[0..i]

leftMin[] : An element leftMin[i] of this 
            array stores the minimum value
            in subarray arr[0..i]

rightMax[] : An element rightMax[i] of this 
             array stores the maximum value 
             in subarray arr[i+1..n-1]

rightMin[] : An element rightMin[i] of this
             array stores the minimum value
             in subarray arr[i+1..n-1] 

我们可以使用 Kadane 算法在 O(n) 时间内构建以上四个数组。

    为了计算位于 arr[0…i] 中的最大和子数组,我们从 0 到 n-1 运行 Kadane 算法并找到位于 arr[i+1 … n-1] 中的最大和子数组,我们运行 Kadane从 n-1 到 0 的算法。

  1. Kadane 的算法也可以修改为找到子数组的最小绝对和。这个想法是改变数组中每个元素的符号并运行 Kadane 算法来找到位于 arr[0…i] 和 arr[i+1…n-1] 中的最大和子数组。现在反转找到的最大子数组和的符号。这将是我们的最小子数组和。这个想法来自here。

    现在从上面的四个数组,我们可以很容易地找到两个连续子数组之和之间的最大绝对差。对于每个索引 i,取最大值

    1. abs(位于 arr[0…i] 中的最大和子数组 – 位于 arr[i+1…n-1] 中的最小和子数组)
    2. abs(位于 arr[0…i] 中的最小和子数组 – 位于 arr[i+1…n-1] 中的最大和子数组)

    下面是上述想法的实现。

    C++
    // C++ program to find two non-overlapping contiguous
    // sub-arrays such that the absolute difference
    // between the sum of two sub-array is maximum.
    #include 
    using namespace std;
      
    // Find maximum subarray sum for subarray [0..i]
    // using standard Kadane's algorithm. This version of
    // Kadane's Algorithm will work if all numbers are
    // negative.
    int maxLeftSubArraySum(int a[], int size, int sum[])
    {
        int max_so_far = a[0];
        int curr_max = a[0];
        sum[0] = max_so_far;
      
        for (int i = 1; i < size; i++)
        {
            curr_max = max(a[i], curr_max + a[i]);
            max_so_far = max(max_so_far, curr_max);
            sum[i] = max_so_far;
        }
      
        return max_so_far;
    }
      
    // Find maximum subarray sum for subarray [i..n]
    // using Kadane's algorithm. This version of Kadane's
    // Algorithm will work if all numbers are negative
    int maxRightSubArraySum(int a[], int n, int sum[])
    {
        int max_so_far = a[n];
        int curr_max = a[n];
        sum[n] = max_so_far;
      
        for (int i = n-1; i >= 0; i--)
        {
            curr_max = max(a[i], curr_max + a[i]);
            max_so_far = max(max_so_far, curr_max);
            sum[i] = max_so_far;
        }
      
        return max_so_far;
    }
      
    // The function finds two non-overlapping contiguous
    // sub-arrays such that the absolute difference
    // between the sum of two sub-array is maximum.
    int findMaxAbsDiff(int arr[], int n)
    {
        // create and build an array that stores
        // maximum sums of subarrays that lie in
        // arr[0...i]
        int leftMax[n];
        maxLeftSubArraySum(arr, n, leftMax);
      
        // create and build an array that stores
        // maximum sums of subarrays that lie in
        // arr[i+1...n-1]
        int rightMax[n];
        maxRightSubArraySum(arr, n-1, rightMax);
      
        // Invert array (change sign) to find minumum
        // sum subarrays.
        int invertArr[n];
        for (int i = 0; i < n; i++)
            invertArr[i] = -arr[i];
      
        // create and build an array that stores
        // minimum sums of subarrays that lie in
        // arr[0...i]
        int leftMin[n];
        maxLeftSubArraySum(invertArr, n, leftMin);
        for (int i = 0; i < n; i++)
            leftMin[i] = -leftMin[i];
      
        // create and build an array that stores
        // minimum sums of subarrays that lie in
        // arr[i+1...n-1]
        int rightMin[n];
        maxRightSubArraySum(invertArr, n - 1, rightMin);
        for (int i = 0; i < n; i++)
            rightMin[i] = -rightMin[i];
      
        int result = INT_MIN;
        for (int i = 0; i < n - 1; i++)
        {
            /* For each index i, take maximum of
            1. abs(max sum subarray that lies in arr[0...i] -
                min sum subarray that lies in arr[i+1...n-1])
            2. abs(min sum subarray that lies in arr[0...i] -
                max sum subarray that lies in arr[i+1...n-1]) */
            int absValue = max(abs(leftMax[i] - rightMin[i + 1]),
                            abs(leftMin[i] - rightMax[i + 1]));
            if (absValue > result)
                result = absValue;
        }
      
        return result;
    }
      
    // Driver program
    int main()
    {
        int a[] = {-2, -3, 4, -1, -2, 1, 5, -3};
      
        int n = sizeof(a) / sizeof(a[0]);
      
        cout << findMaxAbsDiff(a, n);
      
        return 0;
    }


    Java
    // Java program to find two non-overlapping
    // contiguous sub-arrays such that the 
    // absolute difference
    import java.util.*;
      
    class GFG {
          
        // Find maximum subarray sum for subarray
        // [0..i] using standard Kadane's algorithm.
        // This version of Kadane's Algorithm will 
        // work if all numbers are negative.
        static int maxLeftSubArraySum(int a[], int size, 
                                              int sum[])
        {
            int max_so_far = a[0];
            int curr_max = a[0];
            sum[0] = max_so_far;
      
            for (int i = 1; i < size; i++) {
                curr_max = Math.max(a[i], curr_max + a[i]);
                max_so_far = Math.max(max_so_far, curr_max);
                sum[i] = max_so_far;
            }
      
            return max_so_far;
        }
      
        // Find maximum subarray sum for subarray [i..n]
        // using Kadane's algorithm. This version of Kadane's
        // Algorithm will work if all numbers are negative
        static int maxRightSubArraySum(int a[], int n, int sum[])
        {
            int max_so_far = a[n];
            int curr_max = a[n];
            sum[n] = max_so_far;
      
            for (int i = n - 1; i >= 0; i--) {
                curr_max = Math.max(a[i], curr_max + a[i]);
                max_so_far = Math.max(max_so_far, curr_max);
                sum[i] = max_so_far;
            }
      
            return max_so_far;
        }
      
        // The function finds two non-overlapping contiguous
        // sub-arrays such that the absolute difference
        // between the sum of two sub-array is maximum.
        static int findMaxAbsDiff(int arr[], int n)
        {
            // create and build an array that stores
            // maximum sums of subarrays that lie in
            // arr[0...i]
            int leftMax[] = new int[n];
            maxLeftSubArraySum(arr, n, leftMax);
      
            // create and build an array that stores
            // maximum sums of subarrays that lie in
            // arr[i+1...n-1]
            int rightMax[] = new int[n];
            maxRightSubArraySum(arr, n - 1, rightMax);
      
            // Invert array (change sign) to find minumum
            // sum subarrays.
            int invertArr[] = new int[n];
            for (int i = 0; i < n; i++)
                invertArr[i] = -arr[i];
      
            // create and build an array that stores
            // minimum sums of subarrays that lie in
            // arr[0...i]
            int leftMin[] = new int[n];
            maxLeftSubArraySum(invertArr, n, leftMin);
            for (int i = 0; i < n; i++)
                leftMin[i] = -leftMin[i];
      
            // create and build an array that stores
            // minimum sums of subarrays that lie in
            // arr[i+1...n-1]
            int rightMin[] = new int[n];
            maxRightSubArraySum(invertArr, n - 1, rightMin);
            for (int i = 0; i < n; i++)
                rightMin[i] = -rightMin[i];
      
            int result = -2147483648;
            for (int i = 0; i < n - 1; i++) {
                  
            /* For each index i, take maximum of
            1. abs(max sum subarray that lies in arr[0...i] -
                min sum subarray that lies in arr[i+1...n-1])
            2. abs(min sum subarray that lies in arr[0...i] -
                max sum subarray that lies in arr[i+1...n-1]) */
                int absValue = Math.max(Math.abs(leftMax[i] - rightMin[i + 1]),
                                        Math.abs(leftMin[i] - rightMax[i + 1]));
                if (absValue > result)
                    result = absValue;
            }
      
            return result;
        }
          
        // driver code
        public static void main(String[] args)
        {
            int a[] = { -2, -3, 4, -1, -2, 1, 5, -3 };
            int n = a.length;
            System.out.print(findMaxAbsDiff(a, n));
        }
    }
      
    // This code is contributed by Anant Agarwal.


    Python3
    # Python3 program to find two non-
    # overlapping contiguous sub-arrays
    # such that the absolute difference
    # between the sum of two sub-array is maximum.
      
    # Find maximum subarray sum for
    # subarray [0..i] using standard
    # Kadane's algorithm. This version 
    # of Kadane's Algorithm will work if 
    # all numbers are negative.
    def maxLeftSubArraySum(a, size, sum):
      
        max_so_far = a[0]
        curr_max = a[0]
        sum[0] = max_so_far
      
        for i in range(1, size):
          
            curr_max = max(a[i], curr_max + a[i])
            max_so_far = max(max_so_far, curr_max)
            sum[i] = max_so_far
          
        return max_so_far
      
    # Find maximum subarray sum for
    # subarray [i..n] using Kadane's
    # algorithm. This version of Kadane's
    # Algorithm will work if all numbers are negative
    def maxRightSubArraySum(a, n, sum):
      
        max_so_far = a[n]
        curr_max = a[n]
        sum[n] = max_so_far
      
        for i in range(n - 1, -1, -1):
          
            curr_max = max(a[i], curr_max + a[i])
            max_so_far = max(max_so_far, curr_max)
            sum[i] = max_so_far
      
        return max_so_far
      
    # The function finds two non-overlapping
    # contiguous sub-arrays such that the
    # absolute difference between the sum
    # of two sub-array is maximum.
    def findMaxAbsDiff(arr, n):
      
        # create and build an array that 
        # stores maximum sums of subarrays 
        # that lie in arr[0...i]
        leftMax = [0 for i in range(n)]
        maxLeftSubArraySum(arr, n, leftMax)
      
        # create and build an array that stores
        # maximum sums of subarrays that lie in
        # arr[i+1...n-1]
        rightMax = [0 for i in range(n)]
        maxRightSubArraySum(arr, n-1, rightMax)
      
        # Invert array (change sign) to 
        # find minumum sum subarrays.
        invertArr = [0 for i in range(n)]
        for i in range(n):
            invertArr[i] = -arr[i]
      
        # create and build an array that stores
        # minimum sums of subarrays that lie in
        # arr[0...i]
        leftMin = [0 for i in range(n)]
        maxLeftSubArraySum(invertArr, n, leftMin)
        for i in range(n):
            leftMin[i] = -leftMin[i]
      
        # create and build an array that stores
        # minimum sums of subarrays that lie in
        # arr[i+1...n-1]
        rightMin = [0 for i in range(n)]
        maxRightSubArraySum(invertArr, n - 1, rightMin)
        for i in range(n):
            rightMin[i] = -rightMin[i]
      
        result = -2147483648
        for i in range(n - 1):
          
            ''' For each index i, take maximum of
            1. abs(max sum subarray that lies in arr[0...i] -
                min sum subarray that lies in arr[i+1...n-1])
            2. abs(min sum subarray that lies in arr[0...i] -
                max sum subarray that lies in arr[i+1...n-1]) '''
            absValue = max(abs(leftMax[i] - rightMin[i + 1]),
                           abs(leftMin[i] - rightMax[i + 1]))
            if (absValue > result):
                result = absValue
          
        return result
          
    # Driver Code
    a = [-2, -3, 4, -1, -2, 1, 5, -3]
    n = len(a)
    print(findMaxAbsDiff(a, n))
      
    # This code is contributed by Anant Agarwal.


    C#
    // C# program to find two non-overlapping 
    // contiguous sub-arrays such that the
    // absolute difference
    using System;
    class GFG {
          
    // Find maximum subarray sum for subarray
    // [0..i] using standard Kadane's algorithm.
    // This version of Kadane's Algorithm will
    // work if all numbers are negative.
    static int maxLeftSubArraySum(int []a, int size, 
                                          int []sum)
    {
        int max_so_far = a[0];
        int curr_max = a[0];
        sum[0] = max_so_far;
       
        for (int i = 1; i < size; i++)
        {
            curr_max = Math.Max(a[i], curr_max + a[i]);
            max_so_far = Math.Max(max_so_far, curr_max);
            sum[i] = max_so_far;
        }
       
        return max_so_far;
    }
       
    // Find maximum subarray sum for subarray
    // [i..n] using Kadane's algorithm. 
    // This version of Kadane's Algorithm will
    // work if all numbers are negative
    static int maxRightSubArraySum(int []a, int n,
                                        int []sum)
    {
        int max_so_far = a[n];
        int curr_max = a[n];
        sum[n] = max_so_far;
       
        for (int i = n-1; i >= 0; i--)
        {
            curr_max = Math.Max(a[i], curr_max + a[i]);
            max_so_far = Math.Max(max_so_far, curr_max);
            sum[i] = max_so_far;
        }
       
        return max_so_far;
    }
       
    // The function finds two non-overlapping
    // contiguous sub-arrays such that the 
    // absolute difference between the sum 
    // of two sub-array is maximum.
    static int findMaxAbsDiff(int []arr, int n)
    {
        // create and build an array that stores
        // maximum sums of subarrays that lie in
        // arr[0...i]
        int []leftMax=new int[n];
        maxLeftSubArraySum(arr, n, leftMax);
       
        // create and build an array that stores
        // maximum sums of subarrays that lie in
        // arr[i+1...n-1]
        int []rightMax=new int[n];
        maxRightSubArraySum(arr, n-1, rightMax);
       
        // Invert array (change sign) to find minumum
        // sum subarrays.
        int []invertArr=new int[n];
        for (int i = 0; i < n; i++)
            invertArr[i] = -arr[i];
       
        // create and build an array that stores
        // minimum sums of subarrays that lie in
        // arr[0...i]
        int []leftMin=new int[n];
        maxLeftSubArraySum(invertArr, n, leftMin);
        for (int i = 0; i < n; i++)
            leftMin[i] = -leftMin[i];
       
        // create and build an array that stores
        // minimum sums of subarrays that lie in
        // arr[i+1...n-1]
        int []rightMin=new int[n];
        maxRightSubArraySum(invertArr, n - 1, rightMin);
        for (int i = 0; i < n; i++)
            rightMin[i] = -rightMin[i];
       
        int result = -2147483648;
        for (int i = 0; i < n - 1; i++)
        {
            /* For each index i, take maximum of
            1. abs(max sum subarray that lies in arr[0...i] -
                min sum subarray that lies in arr[i+1...n-1])
            2. abs(min sum subarray that lies in arr[0...i] -
                max sum subarray that lies in arr[i+1...n-1]) */
            int absValue = Math.Max(Math.Abs(leftMax[i] - rightMin[i + 1]),
                                   Math.Abs(leftMin[i] - rightMax[i + 1]));
            if (absValue > result)
                result = absValue;
        }
       
        return result;
    }
      
    //driver code
    public static void Main()
    {
        int []a= {-2, -3, 4, -1, -2, 1, 5, -3};
        int n = a.Length;
        Console.Write(findMaxAbsDiff(a, n));
    }
    }
      
    //This code is contributed by Anant Agarwal.


    PHP
    = 0; $i--)
        {
            $curr_max = max($a[$i],
                            $curr_max + $a[$i]);
            $max_so_far = max($max_so_far,
                              $curr_max);
            $sum[$i] = $max_so_far;
        }
      
        return $max_so_far;
    }
      
    // The function finds two non-overlapping 
    // contiguous sub-arrays such that the 
    // absolute difference between the sum of
    // two sub-array is maximum.
    function findMaxAbsDiff(&$arr, $n)
    {
        // create and build an array that stores
        // maximum sums of subarrays that lie in
        // arr[0...i]
        $leftMax = array_fill(0, $n, NULL);
        maxLeftSubArraySum($arr, $n, $leftMax);
      
        // create and build an array that stores
        // maximum sums of subarrays that lie in
        // arr[i+1...n-1]
        $rightMax = array_fill(0, $n, NULL);
        maxRightSubArraySum($arr, $n - 1, $rightMax);
      
        // Invert array (change sign) to 
        // find minumum sum subarrays
        $invertArr = array_fill(0, $n, NULL);
        for ($i = 0; $i < $n; $i++)
            $invertArr[$i] = -$arr[$i];
      
        // create and build an array that stores
        // minimum sums of subarrays that lie in
        // arr[0...i]
        $leftMin = array_fill(0, $n, NULL);
        maxLeftSubArraySum($invertArr, $n,
                           $leftMin);
        for ($i = 0; $i < $n; $i++)
            $leftMin[$i] = -$leftMin[$i];
      
        // create and build an array that stores
        // minimum sums of subarrays that lie in
        // arr[i+1...n-1]
        $rightMin = array_fill(0, $n, NULL);
        maxRightSubArraySum($invertArr, 
                            $n - 1, $rightMin);
        for ($i = 0; $i < $n; $i++)
            $rightMin[$i] = -$rightMin[$i];
      
        $result = PHP_INT_MIN;
        for ($i = 0; $i <$n - 1; $i++)
        {
            /* For each index i, take maximum of
            1. abs(max sum subarray that lies 
               in arr[0...i] - min sum subarray 
               that lies in arr[i+1...n-1])
            2. abs(min sum subarray that lies 
               in arr[0...i] - max sum subarray
               that lies in arr[i+1...n-1]) */
            $absValue = max(abs($leftMax[$i] -  
                                $rightMin[$i + 1]),
                            abs($leftMin[$i] - 
                                $rightMax[$i + 1]));
            if ($absValue > $result)
                $result = $absValue;
        }
      
        return $result;
    }
      
    // Driver Code
    $a = array(-2, -3, 4, -1, -2, 1, 5, -3);
      
    $n = sizeof($a);
      
    echo findMaxAbsDiff($a, $n);
      
    // This code is contributed
    // by ChitraNayal
    ?>


    输出 :

    12

    时间复杂度为 O(n),其中 n 是输入数组中的元素数。所需的辅助空间是 O(n)。

    如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程