给定一个整数数组和一个整数值k, 找出k个子数组(可能重叠), 它们具有k个最大和。
例子:
Input : arr = {4, -8, 9, -4, 1, -8, -1, 6}, k = 4
Output : 9 6 6 5
Input : arr = {-2, -3, 4, -1, -2, 1, 5, -3}, k= 3
Output : 7 6 5
使用Kadane的算法我们可以找到一个数组的最大连续子数组总和。但是在这种情况下Kadane的算法不起作用。正如我们在数组中命中负数时一样, 将max_ending_here变量设置为零, 因此我们错过了第二个最大值的可能性。
这是我们提出的一种算法宋恩培和高冈忠雄计算最大子阵列和问题在O(n)时间中, k个最大子数组和问题在O(k * n)时间中。
首先, 我们使用这种方法研究仅最大子数组和的问题:
先决条件:
- 前缀和数组
- O(n)中使用前缀和的最大子数组和
k个最大子数组的方法:
1. Calculate the prefix sum of the input array.
2. Take cand, maxi and mini as arrays of size k.
3. Initialize mini[0] = 0 for the same reason as previous.
4. for each value of the prefix_sum[i] do
(i). update cand[j] value by prefix_sum[i] - mini[j]
(ii). maxi will be the maximum k elements of maxi and cand
(iii). if prefix_sum is less than all values of mini, then
include it in mini and remove the maximum element from mini
// After the ith iteration mini holds k minimum prefix sum upto
// index i and maxi holds k maximum overlapping sub-array sums
// upto index i.
5. return maxi
在整个计算方法中, 我们将maxi保持不变, 而mini则保持不变。
C ++
// C++ program to find out k maximum sum of
// overlapping sub-arrays
#include
#include
#include
using namespace std;
// Function to compute prefix-sum of the input array
vector< int > prefix_sum(vector< int > arr, int n)
{
vector< int > pre_sum;
pre_sum.push_back(arr[0]);
for ( int i = 1; i < n; i++)
pre_sum.push_back(pre_sum[i - 1] + arr[i]);
return pre_sum;
}
// Update maxi by k maximum values from maxi and cand
void maxMerge(vector< int >& maxi, vector< int > cand)
{
// Here cand and maxi arrays are in non-increasing
// order beforehand. Now, j is the index of the
// next cand element and i is the index of next
// maxi element. Traverse through maxi array.
// If cand[j] > maxi[i] insert cand[j] at the ith
// position in the maxi array and remove the minimum
// element of the maxi array i.e. the last element
// and increase j by 1 i.e. take the next element
// from cand.
int k = maxi.size();
int j = 0;
for ( int i = 0; i < k; i++) {
if (cand[j] > maxi[i]) {
maxi.insert(maxi.begin() + i, cand[j]);
maxi.erase(maxi.begin() + k);
j += 1;
}
}
}
// Insert prefix_sum[i] to mini array if needed
void insertMini(vector< int >& mini, int pre_sum)
{
// Traverse the mini array from left to right.
// If prefix_sum[i] is less than any element
// then insert prefix_sum[i] at that position
// and delete maximum element of the mini array
// i.e. the rightmost element from the array.
int k = mini.size();
for ( int i = 0; i < k; i++) {
if (pre_sum < mini[i]) {
mini.insert(mini.begin() + i, pre_sum);
mini.erase(mini.begin() + k);
break ;
}
}
}
// Function to compute k maximum overlapping sub-
// array sums
void kMaxOvSubArray(vector< int > arr, int k)
{
int n = arr.size();
// Compute the prefix sum of the input array.
vector< int > pre_sum = prefix_sum(arr, n);
// Set all the elements of mini as +infinite
// except 0th. Set the 0th element as 0.
vector< int > mini(k, numeric_limits< int >::max());
mini[0] = 0;
// Set all the elements of maxi as -infinite.
vector< int > maxi(k, numeric_limits< int >::min());
// Initialize cand array.
vector< int > cand(k);
// For each element of the prefix_sum array do:
// compute the cand array.
// take k maximum values from maxi and cand
// using maxmerge function.
// insert prefix_sum[i] to mini array if needed
// using insertMini function.
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < k; j++) {
if (pre_sum[i] < 0 && mini[j]==numeric_limits< int >::max())
cand[j]=(-pre_sum[i])-mini[j];
else cand[j] = pre_sum[i] - mini[j];
}
maxMerge(maxi, cand);
insertMini(mini, pre_sum[i]);
}
// Elements of maxi array is the k
// maximum overlapping sub-array sums.
// Print out the elements of maxi array.
for ( int ele : maxi)
cout << ele << " " ;
cout << endl;
}
// Driver Program
int main()
{
// Test case 1
vector< int > arr1 = { 4, -8, 9, -4, 1, -8, -1, 6 };
int k1 = 4;
kMaxOvSubArray(arr1, k1);
// Test case 2
vector< int > arr2 = { -2, -3, 4, -1, -2, 1, 5, -3 };
int k2 = 3;
kMaxOvSubArray(arr2, k2);
return 0;
}
Python3
# Python program to find out k maximum sum of
# overlapping sub-arrays
# Function to compute prefix-sum of the input array
def prefix_sum(arr, n):
pre_sum = list ()
pre_sum.append(arr[ 0 ])
for i in range ( 1 , n):
pre_sum.append(pre_sum[i - 1 ] + arr[i])
return pre_sum
# Update maxi by k maximum values from maxi and cand
def maxMerge(maxi, cand):
# Here cand and maxi arrays are in non-increasing
# order beforehand. Now, j is the index of the
# next cand element and i is the index of next
# maxi element. Traverse through maxi array.
# If cand[j] > maxi[i] insert cand[j] at the ith
# position in the maxi array and remove the minimum
# element of the maxi array i.e. the last element
# and increase j by 1 i.e. take the next element
# from cand.
k = len (maxi)
j = 0
for i in range (k):
if (cand[j] > maxi[i]):
maxi.insert(i, cand[j])
del maxi[ - 1 ]
j + = 1
# Insert prefix_sum[i] to mini array if needed
def insertMini(mini, pre_sum):
# Traverse the mini array from left to right.
# If prefix_sum[i] is less than any element
# then insert prefix_sum[i] at that position
# and delete maximum element of the mini array
# i.e. the rightmost element from the array.
k = len (mini)
for i in range (k):
if (pre_sum < mini[i]):
mini.insert(i, pre_sum)
del mini[ - 1 ]
break
# Function to compute k maximum overlapping sub-array sums
def kMaxOvSubArray(arr, k):
n = len (arr)
# Compute the prefix sum of the input array.
pre_sum = prefix_sum(arr, n)
# Set all the elements of mini as + infinite
# except 0th. Set the 0th element as 0.
mini = [ float ( 'inf' ) for i in range (k)]
mini[ 0 ] = 0
# Set all the elements of maxi as -infinite.
maxi = [ - float ( 'inf' ) for i in range (k)]
# Initialize cand array.
cand = [ 0 for i in range (k)]
# For each element of the prefix_sum array do:
# compute the cand array.
# take k maximum values from maxi and cand
# using maxmerge function.
# insert prefix_sum[i] to mini array if needed
# using insertMini function.
for i in range (n):
for j in range (k):
cand[j] = pre_sum[i] - mini[j]
maxMerge(maxi, cand)
insertMini(mini, pre_sum[i])
# Elements of maxi array is the k
# maximum overlapping sub-array sums.
# Print out the elements of maxi array.
for ele in maxi:
print (ele, end = ' ' )
print ('')
# Driver Program
# Test case 1
arr1 = [ 4 , - 8 , 9 , - 4 , 1 , - 8 , - 1 , 6 ]
k1 = 4
kMaxOvSubArray(arr1, k1)
# Test case 2
arr2 = [ - 2 , - 3 , 4 , - 1 , - 2 , 1 , 5 , - 3 ]
k2 = 3
kMaxOvSubArray(arr2, k2)
输出如下:
9 6 6 5
7 6 5
时间复杂度:" insertMini"和" maxMerge"函数的运行时间为O(k), 而更新" cand"数组则需要O(k)时间。我们执行此过程n次。因此, 整体时间复杂度为O(k * n).
更多数据结构和算法相关内容请参考:lsbin - IT开发技术:https://www.lsbin.com/
查看以下更多算法相关的内容: