给定一个整数数组,找出两个不重叠的连续子数组,使得两个子数组之和的绝对差最大。
例子:
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) 时间内构建以上四个数组。
- Kadane 的算法也可以修改为找到子数组的最小绝对和。这个想法是改变数组中每个元素的符号并运行 Kadane 算法来找到位于 arr[0…i] 和 arr[i+1…n-1] 中的最大和子数组。现在反转找到的最大子数组和的符号。这将是我们的最小子数组和。这个想法来自here。
现在从上面的四个数组,我们可以很容易地找到两个连续子数组之和之间的最大绝对差。对于每个索引 i,取最大值
- abs(位于 arr[0…i] 中的最大和子数组 – 位于 arr[i+1…n-1] 中的最小和子数组)
- 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 现场工作专业课程和学生竞争性编程现场课程。
为了计算位于 arr[0…i] 中的最大和子数组,我们从 0 到 n-1 运行 Kadane 算法并找到位于 arr[i+1 … n-1] 中的最大和子数组,我们运行 Kadane从 n-1 到 0 的算法。