Partition an array into K subarrays with minimal difference - c

DISCLAIMER:
Described problem looks like a task from a competition. I'm not participating in any of them, I'm not aware about any ongoing competitions, which might involve the problem. If there are any of them, I'll close the question to stay fair!
I have a problem:
given an array A of values and integer K, split A into exactly K non-overlapping contiguous subarrays in such way that difference between a subarray with minimal and a subarray maximum sums is minimal. It is allowed to rotate A by any number in any direction.
Consider an example:
Input: A = [5 1 1 1 3 2], K = 3
Output: [5][1 1 1][3 2], maximum sum = 5, minimum sum = 3, result = 2
I have partially working code (terribly ugly, my bad, but it does not meant to be production quality):
#include <climits>
#include <cstdio>
#include <cstring>
const int max_n = 50;
const int max_k = 20;
int deps[max_n];
int max (int x, int y) {
return x > y ? x : y;
}
int min (int x, int y) {
return x < y ? x : y;
}
int sum (int a[], int start, int end) {
int res = 0;
for (int i = start; i <= end; ++i) res += a[i];
return res;
}
int k_partitioning(int k, int n, int deps[]) {
int res = INT_MAX;
// consider all possible rotations/shifts
for(int offset = 0; offset < n; ++offset) {
for(int l_min = 0; l_min < n; ++l_min) {
for(int r_min = l_min; r_min < n; ++r_min) {
// check minimal sum subarray
int min_sum = sum (deps, l_min, r_min);
int dp[k][n];
for (int s = 0; s < k; ++s) {
for (int q = 0; q < n; ++q) {
dp[s][q] = 0;
}
}
// assuming that current sum is a target sum
dp[0][r_min-l_min] = min_sum;
for(int p = 1; p < k; ++p) {
for(int l_max = 0; l_max < n; ++l_max) {
for(int r_max = 0; r_max < n; ++r_max) {
int max_sum = sum(deps, l_max, r_max);
if (max_sum >= min_sum) dp[p][r_max] = max(dp[p-1][l_max], max_sum);
} // l_maxs
} // r_maxs
} // partitions
// printing dp
// skip incorrect partitioning, when not all K partitions were used
if (dp[k-1][n-1] == 0) continue;
// update difference
res = min (res, dp[k-1][n-1] - min_sum);
} // end min sum seg
} // start min sum seg
//break;
} // cuts
return res;
}
int main(int argc, char* argv[]) {
int k = 0;
scanf("%d", &k);
int n = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &deps[i]);
}
printf ("%d\n", k_partitioning(k, n, deps));
return 0;
}
The idea is simple: assume that current partition has minimal sum, enumerate all possible maximal partitions, setup dynamic programming for generating maximum sum with minimal value, check for difference. Total complexity: O(K*N^4).
My problem is that it fails some tests and I'm stuck with troubleshooting it. Could someone help me with it?
Failed test, for example:
N = 4, K = 2, A = [6 13 10 2]
UPDATE
This version should fix some previous issues. First, it removes wasteful loop over "offsets" and adds just an array rotation in the end of l_min loop. Second, I've noticed, that dp can't be initialized with 0 - this is minimization task, so it should be initialized with some large value (depends on a problem's constants, max_value here already is out of value domain). Finally, intervals should not overlap anymore - each sum exclude left end of an interval. However, it still does not produce expected results.
#include <climits>
#include <cstdio>
#include <cstring>
const int max_value = 200000;
const int max_n = 50;
const int max_k = 20;
int deps[max_n];
int max (int x, int y) {
return x > y ? x : y;
}
int min (int x, int y) {
return x < y ? x : y;
}
int sum (int a[], int start, int end) {
int res = 0;
for (int i = start; i <= end; ++i) res += a[i];
return res;
}
int k_partitioning(int k, int n, int deps[]) {
int res = max_value;
for(int l_min = 0; l_min < n; ++l_min) {
for(int r_min = l_min; r_min < n; ++r_min) {
int min_sum = sum (deps, l_min+1, r_min);
int dp[k][n];
for (int s = 0; s < k; ++s) {
for (int q = 0; q < n; ++q) {
dp[s][q] = max_value;
}
}
// assuming that current sum is a target sum
dp[0][r_min-l_min] = min_sum;
for(int p = 1; p < k; ++p) {
for(int l_max = 0; l_max < n; ++l_max) {
for(int r_max = l_max; r_max < n; ++r_max) {
int max_sum = sum(deps, l_max+1, r_max);
if (max_sum >= min_sum) dp[p][r_max] = max(dp[p-1][l_max], max_sum);
} // l_maxs
} // r_maxs
} // partitions
// skip incorrect partitioning, when not all K partitions were used
if (dp[k-1][n-1] == max_value) continue;
// update difference
res = min (res, dp[k-1][n-1] - min_sum);
} // end min sum seg
// rotate an array to consider different starting points
int tmp[n];
for (int i = 0; i < n; ++i) {
int new_idx = i + n + 1;
tmp[new_idx % n] = deps[i];
}
for(int i = 0; i < n; ++i) deps[i] = tmp[i];
} // start min sum seg
return res;
}
int main(int argc, char* argv[]) {
int k = 0;
scanf("%d", &k);
int n = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &deps[i]);
}
printf ("%d\n", k_partitioning(k, n, deps));
return 0;
}

Ok, I think I did it!
The idea is following: we assume that minimum sum interval always starts from 0. Then we start to enumerate maximum sum intervals, starting from the right boundary of the minimal interval. We build DP problem for current max interval to determine a minimum maximal sum. After that you update result and rotate an array by one.
My code is not perfect in a way that I compute current sums each iteration. One can pre-compute them and just index them each time.
This code might have some bugs, but it passes all test that I have.
#include <climits>
#include <cstdio>
#include <cstring>
const int max_value = 200000;
const int max_n = 50;
const int max_k = 20;
int deps[max_n];
int max (int x, int y) {
return x > y ? x : y;
}
int min (int x, int y) {
return x < y ? x : y;
}
int sum (int a[], int start, int end) {
int res = 0;
for (int i = start; i <= end; ++i) res += a[i];
return res;
}
int k_partitioning(int k, int n, int deps[]) {
int res = max_value;
for(int offset = 0; offset < n; ++offset) {
int l_min = 0;
for(int r_min = l_min; r_min < n; ++r_min) {
int min_sum = sum (deps, l_min, r_min);
int dp[k][n];
for (int s = 0; s < k; ++s) {
for (int q = 0; q < n; ++q) {
dp[s][q] = max_value;
}
}
// assuming that current sum is a target sum
dp[0][r_min-l_min] = min_sum;
for(int p = 1; p < k; ++p) {
for(int l_max = r_min; l_max < n; ++l_max) {
for(int r_max = l_max; r_max < n; ++r_max) {
int max_sum = sum(deps, l_max+1, r_max);
if (max_sum >= min_sum) {
dp[p][r_max] = min(dp[p][r_max], max(dp[p-1][l_max], max_sum));
}
} // l_maxs
} // r_maxs
} // partitions
// skip incorrect partitioning, when not all K partitions were used
if (dp[k-1][n-1] == max_value) continue;
// update difference
res = min (res, dp[k-1][n-1] - min_sum);
} // end min sum seg
int tmp[n];
for (int i = 0; i < n; ++i) {
int new_idx = i + n - 1;
tmp[new_idx % n] = deps[i];
}
for(int i = 0; i < n; ++i) deps[i] = tmp[i];
} // start min sum seg
return res;
}
int main(int argc, char* argv[]) {
int k = 0;
scanf("%d", &k);
int n = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &deps[i]);
}
printf ("%d\n", k_partitioning(k, n, deps));
return 0;
}

Solution without rotations:
1) Compute max M and total S of the array - O(n)
2) Let there be a function F(P), which returns True if it is possible to get a Sum P or less with k (>= 0) partitions still remaining.
3) Do a binary search on range(M, S) using F. - O(log(S-M))
4) Logic behind F: Fill a bucket till it's not greater than S/K. Then move onto next bucket. If there are still items remaining and no buckets remaining, then the answer is false - O(n)
Time Complexity = O(n) + O(n) * (log(S-M)) = O(n*log(S-M))
Solution with Rotations:
For all rotations in [0, 1, ... N-1], compute min sum.
Total Time Complexity = O(n) * O(nlog(S-M)) = O(n^2*log(S-M))

Now that you've got your code working, here's an alternative method :)
Consider that for each k, we can pair a sum growing from A[i] to the left (sum A[i-j..i]) with all available intervals recorded for f(k-1, i-j-1) and update them - for each interval, (low, high), if the sum is greater than high, then new_interval = (low, sum) and if the sum is lower than low, then new_interval = (sum, high); otherwise, the interval stays the same. For example,
i: 0 1 2 3 4 5
A: [5 1 1 1 3 2]
k = 3
i = 3, j = 0
The ordered intervals available for f(3-1, 3-0-1) = f(2,2) are:
(2,5), (1,6) // These were the sums, (A[1..2], A[0]) and (A[2], A[0..1])
Sum = A[3..3-0] = 1
Update intervals: (2,5) -> (1,5)
(1,6) -> (1,6) no change
Now, we can make this iteration much more efficient by recognizing and pruning intervals during the previous k round.
Watch:
A: [5 1 1 1 3 2]
K = 1:
N = 0..5; Intervals: (5,5), (6,6), (7,7), (8,8), (11,11), (13,13)
K = 2:
N = 0: Intervals: N/A
N = 1: Intervals: (1,5)
N = 2: (1,6), (2,5)
Prune: remove (1,6) since any sum <= 1 would be better paired with (2,5)
and any sum >= 6 would be better paired with (2,5)
N = 3: (1,7), (2,6), (3,5)
Prune: remove (2,6) and (1,7)
N = 4: (3,8), (4,7), (5,6), (5,6)
Prune: remove (3,8) and (4,7)
N = 5: (2,11), (5,8), (6,7)
Prune: remove (2,11) and (5,8)
For k = 2, we are now left with the following pruned record:
{
k: 2,
n: {
1: (1,5),
2: (2,5),
3: (3,5),
4: (5,6),
5: (6,7)
}
}
We've cut down the iteration of k = 3 from a list of n choose 2 possible splits to n relevant splits!
The general algorithm applied to k = 3:
for k' = 1 to k
for sum A[i-j..i], for i <- [k'-1..n], j <- [0..i-k'+1]:
for interval in record[k'-1][i-j-1]: // records are for [k'][n']
update interval
prune intervals in k'
k' = 3
i = 2
sum = 1, record[2][1] = (1,5) -> no change
i = 3
// sums are accumulating right to left starting from A[i]
sum = 1, record[2][2] = (2,5) -> (1,5)
sum = 2, record[2][1] = (1,5) -> no change
i = 4
sum = 3, record[2][3] = (3,5) -> no change
sum = 4, record[2][2] = (2,5) -> no change
sum = 5, record[2][1] = (1,5) -> no change
i = 5
sum = 2, record[2][4] = (5,6) -> (2,6)
sum = 5, record[2][3] = (3,5) -> no change
sum = 6, record[2][2] = (2,5) -> (2,6)
sum = 7, record[2][1] = (1,5) -> (1,7)
The answer is 5 paired with record[2][3] = (3,5), yielding the updated interval, (3,5). I'll leave the pruning logic for the reader to work out. If we wanted to continue, here's the pruned list for k = 3
{
k: 3
n: {
2: (1,5),
3: (1,5),
4: (3,5),
5: (3,5)
}
}

I finally solved this question : Split array into three subarrays, It may help you.
here I'm splitting a array into three sub-array with java.
package com.array2;
public class SplitArray {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = { 1, 2, 3, 5, 4, 6, 9, 8, 15, 52, 4, 6, 89 };
splitArray(a);
}
private static void splitArray(int[] a) {
// TODO Auto-generated method stub
int a_l = a.length;
int[] a1 = new int[a.length / 3];
int[] a2 = new int[a.length / 3];
int[] a3 = new int[a.length / 3 + a.length % 3];
for (int i = 0; i < a3.length; i++) {
if (i < a1.length) {
a1[i] = a[i];
a2[i] = a[a1.length + i];
a3[i] = a[a1.length + a2.length + i];
} else {
a3[i] = a[a1.length + a2.length + i];
}
}
}
}

Related

Recursive Staircase Problem but with path printing

I'm working on this recursive staircase problem where the total steps and the steps you can take at a time are variable in C. I've found this very good code that does exactly that, but unfortunatly it only prints out the number of solutions instead of all the different path possibilities. For example: 4 steps, 4 steps at a time:
1-1-1-1
1-1-2
1-2-1
1-3
2-1-1
2-2
3-1
4
That's the code:
int countWays(int n, int m)
{
int res[n + 1];
int temp = 0;
res[0] = 1;
for (int i = 1; i <= n; i++) {
int s = i - m - 1;
int e = i - 1;
if (s >= 0) {
temp -= res[s];
}
temp += res[e];
res[i] = temp;
}
return res[n];
}
int main()
{
int n = 5, m = 3;
printf("Number of ways = %d",
countWays(n, m));
return 0;
}

Count Number of distinct subarrays

I recently came across this question in one of the coding interviews. The question is as follows:
Given an array A[] of n numbers and a number k, count the total number of distinct subarrays such that each subarray contains at most k odd elements.
1 <= n <= 1000
1 <= A[i] <= 250
1 <= k <= n
I used a DP approach to solve the problem, but my solution does not take care of the distinct part.
public int distinctSubArraysWithAtmostKOddElements(int[] a, int k) {
int l = a.length;
int[][] dp = new int[k + 1][l];
for (int j = 0; j < l; j++) {
dp[0][j] = a[j] % 2 == 0 ? 1 : 0;
}
for (int i = 1; i <= k; i++) {
dp[i][0] = 1;
}
for (int j = 1; j <= k; j++) {
for (int i = 1; i < l; i++) {
if (a[i] % 2 == 0) {
dp[j][i] = Math.max(dp[j - 1][i], 1 + Math.max(dp[j - 1][i - 1], dp[j][i - 1]));
} else {
dp[j][i] = Math.max(dp[j - 1][i], 1 + dp[j - 1][i - 1]);
}
}
}
int tot = 0;
for (int i = 0; i < l; i++) {
tot += dp[k][i];
}
return tot;
}
My solution works in O(nk) time and space.
How can I take care of the distinctness ? Is there a mathematical formula that solves this problem?
Edit:
Eg 1:
A[] = {2,1,2,3} and k = 1
Distinct Subarrays are: {2}, {2,1}, {1}, {1,2}, {2,1,2}, {3}, {2,3}
So answer is 7.
Eg 2:
A[] = {1,1,1} and k = 2
Distinct Subarrays are: {1}, {1,1}
So answer is 2.
Eg 3:
A[] = {1,2,3} and k = 1
Distinct Subarrays are: {1}, {2}, {3}, {1,2}, {2,3}
So answer is 5.
We can iterate over all subarrays and store the hashes of the valid subarrays.The time complexity is O((n^2)*log(n)) and memory complexity O(n^2).
int distinctSubArraysWithAtmostKOddElements(vector<int> a, int k)
{
set<unsigned long long int> hashes;
int prime = 163;
for(int i = 0 ; i < a.size() ; i++)
{
int oddNow = 0;
unsigned long long int hashNow = 0;
for(int j = i ; j < a.size() ; j++)
{
hashNow = hashNow * prime + a[j];
if( a[j] % 2) oddNow++;
if(oddNow <= k)
hashes.insert(hashNow);
else
break;
}
}
return hashes.size();
}

How to find the items in the optimal solution of the knapsack problem using dynamic programming?

I want to find which items are eventually chosen in the optimal solution of the knapsack problem using the method of dynamic programming.
This is my interpretation so far...
#include<stdio.h>
int getMax(int x, int y) {
if(x > y) {
return x;
} else {
return y;
}
}
int main(void) {
//the first element is set to -1 as
//we are storing item from index 1
//in val[] and wt[] array
int val[] = {-1, 100, 20, 60, 40};
int wt[] = {-1, 3, 2, 4, 1};
int A[] = {0,0,0,0,0};
int n = 4; //num
int W = 5;//cap
int i, j;
// value table having n+1 rows and W+1 columns
int V[n+1][W+1];
// fill the row i=0 with value 0
for(j = 0; j <= W; j++) {
V[0][j] = 0;
}
// fill the column w=0 with value 0
for(i = 0; i <= n; i++) {
V[i][0] = 0;
}
//fill the value table
for(i = 1; i <= n; i++) {
for(j = 1; j <= W; j++) {
if(wt[i] <= j) {
V[i][j] = getMax(V[i-1][j], val[i] + V[i-1][j - wt[i]]);
} else {
V[i][j] = V[i-1][j];
}
}
}
//max value that can be put inside the knapsack
printf("Max Value: %d\n", V[n][W]);
//==================================find items
int n1,c;
n1=n;
c=W;
int A2[n1][c];
while(c>0){
if(A2[n1][c]==A2[n1-1][c]){
A[n1]=0;
} else {
A[n1]=1;
}
n1=n1-1;
c=c-wt[n1];
}
printf("Final array of items: ");
for(i = 0; i < n; i++){
printf("%d",A[i]);
}
} // end of main
And this is the output:
Max Value: 140
Final array of items: 0001
This string of ones and zeros is meant to be the finally chosen items, but from the solution this seems to be wrong!
I followed this algorithm:
While the remaining capacity is greater than 0 do
If Table[n, c] = Table[n-1, c] then
Item n has not been included in the optimal solution
Else
Item n has been included in the optimal solution
Process Item n
Move one row up to n-1
Move to column c – weight(n)
So, is this algorithm wrong / not suitable for this method, or am I missing something?

Minimum contiguous sum that can be obtained by performing at most K swaps

I have this homework:
Given an array consisting of N integers, you are required to print the minimum contiguous sum that can be obtained by performing at most K swaps. During a swap any 2 elements of the given array could be swapped.
I tried this
int currentSum = 0;
int currentMin = 0;
for (int j = 0; j < input.Length; j++)
{
if (input[j] >= 0)
continue;
currentSum += input[j];
if (currentMin > currentSum)
currentMin = currentSum;
}
It will give the minimum sum without any swappings, but how can I improve in no more than K swaps?
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.Iterator;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;
class TestClass {
static Scanner scanner;
public static void main(String args[] ) throws Exception {
scanner=new Scanner(System.in);
int T=scanner.nextInt();
while(T>0){
int N=scanner.nextInt();
int K=scanner.nextInt();
int[] array=new int[N];
for(int i=0;i<array.length;i++)
{
array[i]=scanner.nextInt();
}
System.out.println(findingMinimumSumSubarray(array, K));
T--;
}
}
public static int findingMinimumSumSubarray(int[] values, int k) {
int N = values.length;
int res = values[0];
for (int L = 0; L < N; L++) {
for (int R = L; R < N; R++) {
List<Integer> A= new ArrayList<Integer>();
List<Integer> B = new ArrayList<Integer>();
int ashu = 0;
for (int i = 0; i < N; i++) {
if (i >= L && i <= R) {
A.add(values[i]);
ashu += values[i];
} else {
B.add(values[i]);
}
}
Collections.sort(A);
Collections.sort(B);
Collections.reverse(B);
res = Math.min(res, ashu);
for (int t = 1; t <= k; t++) {
if (t > A.size() || t > B.size()) break;
ashu -= A.get(A.size() - t);
ashu += B.get(B.size() - t);
res = Math.min(res, ashu);
}
}
}
return res;
}
}
You solution is not correct even without swap.
Test: [-1, 2, -1]. Your answer on this test is -2. Correct answer: -1
I hope that my solution is not best and there is better approach.
Simple O(N^3) complexity solution.
Let's assume that our final minimum contiguous segment will be [L, R] for some 0 <= L <= R < N. Now we have two multiset: A and B. A - multiset with "inner" numbers (numbers that are inside range [L, R]) and B - multiset with "outer" numbers (numbers that are outside of range [L, R]). Out goal is to minimize sum of numbers in A - sum(A). Making swap inside A or B is meaningful, because it will not affect to sum(A). We can swap one element from A with other element in B. We have no more than K swaps, and it means that no more than K elements in A will be swapped with no more than K elements in B. To reach minimum value of sum(A) we will take some maximum elements in A and swap them with minimum elements in B. For example:
A = {-3, -3, -1, 2}; B = {-4, 1, 3, 6}; K = 2;
We can make 0 swaps, A = {-3, -3, -1, 2}; B = {-4, 1, 3, 6}; then sum(A) == -3
We can make 1 swaps, A = {-3, -3, -1, -4}; B = {2, 1, 3, 6}; then sum(A) == -11
We can make 2 swaps, A = {-3, -3, 1, -4}; B = {2, -1, 3, 6}; then sum(A) == -9
Answer is sum(A) == -11
For range [L, R] we can get minimum possible sum. To obtain answer for our initial problem we will iterate over all possible ranges [L, R]. 0 <= L <= R < N
Naive implementation. O(N^3logn) complexity.
int get_minimum_contiguous_sum(vector <int> values, int k) {
int N = values.size();
int ans = values[0]; // initializing with any possible sums
for (int L = 0; L < N; L++) {
for (int R = L; R < N; R++) {
vector <int> A, B; // our "inner" and "outer" sets
int suma = 0; // will store initial sum of elements in A
for (int i = 0; i < N; i++) {
if (i >= L && i <= R) {
A.push_back(values[i]);
suma += values[i];
} else {
B.push_back(values[i]);
}
}
// Sorting set A in non-descending order
sort(A.begin(), A.end());
// Sorting set B in non-increasing order
sort(B.begin(), B.end());
reverse(B.begin(), B.end());
ans = min(ans, suma); // Updating answer with initial state
// Iterating number of swaps that we will make
for (int t = 1; t <= k; t++) {
// if some of two sets contain less than t elements
// then we cannot provide this number of swaps
if (t > A.size() || t > B.size()) break;
// Swapping t-th maximum of A with t-th minimum of B
// It means that t-th maximum of A subtracts from suma
// and t-th minimum of B added to suma
suma -= A[A.size() - t];
suma += B[B.size() - t];
ans = min(ans, suma);
}
}
}
return ans;
}
Optimization
Let's assume that for the range [L, R] we already know sorted set A and reverse sorted set B. When we will compute for the range [L, R + 1] exactly one element will be deleted from B and inserted in A(this number is exactly values[R+1]). C++ has containers set and multiset that can allow us to insert and remove in O(log) time and iterate in O(n) time. Other programming languages also has same containers (in java it is TreeSet/SortedSet). So when we move R to R+1, we will make some simple queries to multiset(insert/remove).
O(N^3) solution.
int get_minimum_contiguous_sum(vector <int> values, int k) {
int N = values.size();
int ans = values[0]; // initializing with any possible sums
for (int L = 0; L < N; L++) {
// "inner" multiset
// Stores in non-increasing order to iterate from beginning
multiset<int, greater<int> > A;
// "outer" multiset
// multiset by defaul stres in non-decreasing order
multiset<int> B;
// Initially all elements of array in B
for (int i = 0; i < N; i++) {
B.insert(values[i]);
}
int suma = 0; // Empty set has sum=0
for (int R = L; R < N; R++) {// Iterate over all possible R
// Removing element from B and inserting to A
B.erase(B.find(values[R]));
A.insert(values[R]);
suma += values[R];
ans = min(ans, suma);
__typeof(A.begin()) it_a = A.begin();
__typeof(B.begin()) it_b = B.begin();
int cur = suma;
for (int i = 1; i <= k; i++) {
if (it_a != A.end() && it_b != B.end())
break;
cur -= *it_a;
cur += *it_b;
ans = min(ans, cur);
it_a++;
it_b++;
}
}
}
return ans;
}

Return the sub-array of the maximum sum

In the book "elements of programming interviews", I came across, the problem of returning the subarray of the maximum sum. I tried their solution and I don't think we need to keep track of the minimum sum to get the array of the maximum sum:
I wrote another version of it maximumSumMine where I removed the minSum and it worked fine, the output in the comments
What is the purpose of tracking minSum, do we really need it?
#include <stdio.h>
#include <limits.h>
typedef struct range {
int start;
int end;
int maxSum;
} range;
void print(int *a, int start, int end) {
for (int i = start; i <= end; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
// Book's code as it is
range maximumSum(int *a, int n) {
range r;
r.start = 0; r.end = 0;
int minSum = 0, sum = 0, minIndex = -1, maxSum = INT_MIN;
for (int i = 0; i < n; i++) {
sum += a[i];
if (sum < minSum) {
minSum = sum;
minIndex = i;
}
if (sum - minSum > maxSum) {
maxSum = sum - minSum;
r.start = minIndex + 1;
r.end = i + 1;
}
}
return r;
}
range maximumSumMine(int *a, int n) {
range r;
r.start = 0; r.end = 0;
int sum = 0, minIndex = -1, maxSum = INT_MIN;
for (int i = 0; i < n; i++) {
sum += a[i];
if (sum < 0) {
sum = 0;
minIndex = i + 1;
}
if (sum > maxSum) {
maxSum = sum;
r.start = minIndex;
r.end = i;
}
}
return r;
}
void unitTests() {
// Example 1
int a[5] = {-2, 5, 1, -1, 4};
range r = maximumSum(a, 5);
print(a, r.start, r.end); // output 5 1 -1 4 0
// Example 2
int b[5] = {2, -5, 5, -1, 3};
r = maximumSum(b, 5);
print(b, r.start, r.end); // 5 -1 3 1
// Example 1
r = maximumSumMine(a, 5);
print(a, r.start, r.end); // output 5 1 -1 4
// Example 2
r = maximumSum(b, 5);
print(b, r.start, r.end); // 5 -1 3 1
}
int main() {
unitTests();
return 0;
}
You need the minimum sum because the algorithm involves computing prefix sums:
sums[i] = a[0] + a[1] + ... + a[i]
So for each i, the maximum sum you can get that ends at a[i] is sums[i] - min(sums[j < i]).
The book code implements this without actually using an array, as you can simply keep track of the minimum and the current prefix sum.
If you only take the max of the prefix sums under the conditions that you do, it will not work for negative maximum sums: you will always output 0 if the maximum sum is negative, because you will set your prefix sum to 0 when it becomes negative.
Sometimes, ignoring negative maximum sums can be perfectly fine, other times not. I've seen both versions given as programming assignments / questions.
Example:
a = {-1, -2, -3}
book output = -1
your output = 0

Resources