Maximum Sum of Product - algorithm

I have a following problem.
Given N numbers, in range -100..100.
It is required to rearrange elements to have maximum sum of product value.
Sum of Product in this task is defined as A1*A2+A2*A3...AN-1*AN
For example, given numbers 10 20 50 40 30.
Then, we can rearrange them following way:
10, 30, 50, 40, 20 from the left to have maximum 10×30+30×50+50×40+40×20=4600
The idea is to sort the sequence, and then put max number in the middle of new sequence, then put next max number to the right, then to the left, and so on.
But, regarding negative numbers this is not working.
I have tried following algorithm:
1) sort initial sequence
2) process positive numbers and zero values how described above
3) process negative numbers how described above
4) find minimum number from positive sequence, it would be either left or right element and add after of before this number processed negative sequence.
For example, given sequence:
1,-2,3,-4,5,-6,7,-8,9,10,11,12,13,14,15,-16
Expected maximum sum of product is 1342.
My algorithm gives next rearrangements:
3,7,10,12,14,15,13,11,9,5,1,-4,-8,-16,-6,-2
Sum of product is 1340.
This seem to work, but it does not.
Could you please advise?

Your approach is sound, but you have to separate the positive and negative numbers.
Sort the array and split it into left and right parts, one containing all the negative numbers, and one containing all the non-negative numbers. Rearrange them as you were doing before, with the largest (absolute) values in the middle and decreasing values placed alternately on either side, but make sure that the smallest values in each part are at opposite ends.
Specifically, the negative number with the smallest absolute value should be the last element of the left part, and the non-negative value with the smallest value should be the first element of the right part.
Then concatenate the two parts and calculate the sum of adjacent products.
Here's a worked example:
arr = [2, 3, 5, -6, -2, -5]
arr.sort() = [-6, -5, -2, 2, 3, 5]
left, right = [-5, -6, -2], [2, 5, 3]
max_sum_of_product = -5*-6 + -6*-2 + -2*2 + 2*5 + 5*3 = 63
I don't have a formal proof of correctness, but this method gives the same results as a brute force search over all permutations of the input array:
def max_sum_of_products(arr):
from itertools import permutations
n = len(arr)
###### brute force method
max1 = max([sum([a[x-1]*a[x] for x in range(1,n)]) for a in permutations(arr)])
###### split method
lo, hi = [x for x in arr if x<0], [x for x in arr if x>=0]
lo.sort()
hi.sort()
lo_ordered, hi_ordered = [], []
t = (len(lo)%2 == 1)
for x in lo:
if t:
lo_ordered = lo_ordered + [x]
else:
lo_ordered = [x] + lo_ordered
t = not t
t = (len(hi)%2 == 0)
for x in hi[::-1]:
if t:
hi_ordered = hi_ordered + [x]
else:
hi_ordered = [x] + hi_ordered
t = not t
arr = lo_ordered + hi_ordered
max2 = sum([arr[x-1]*arr[x] for x in range(1,n)])
return (max1, max2)
def test():
from random import randint
for i in range(10):
a = []
for j in range(randint(4,9)):
a = a + [randint(-10,10)]
print a,
(max1,max2) = max_sum_of_products(a)
if max2!=max1:
print "bad result :-("
else:
print max1
test()

I have written a method in java that will take the array as an input and return the maximum sum of product pairs as output.
First I compute the negative part, then the positive part and then return their computed sum.
While computing the negative part, if the number of elements are odd, then the remaining element needs to be avoided (as it can be multiplied by 0 and nullified), we do this so that that negative addition will lower the sum.
All other negative items are needed to multiplied in pair and summed.
Then coming to second positive part, when we see 1 we need to add it if number of elements are odd, otherwise simply multiply and go forward.
public static long sum(int arr[]) {
Arrays.sort(arr);
long ans = 0;
long ans1 = 0;
boolean flag = false;
boolean flag2 = false;
int[] arr1 = new int[arr.length];
int[] arr2 = new int[arr.length];
int i = 0;
while (arr[i] < 0) {
arr1[i] = arr[i];
i++;
}
if (arr[i] == 0) flag = true;
if (i % 2 == 0) { //even -6,-5,-3,-2,-1
for (int j = 0; j < i - 1; j += 2) {
ans = arr1[j] * arr1[j + 1];
}
} else {
if (flag) {
for (int j = 0; j < i - 2; j += 2) {
ans = arr1[j] * arr1[j + 1];
}
}
}
int j = 0;
while (i<arr.length) {
arr2[j] = arr[i];
i++;
j++;
}
if (arr2[j] == 1) flag2 = true;
if (i % 2 == 0) {
for (int k=i-1; k>0; k-=2) {
ans1 = arr2[k] * arr2[k-1];
}
if (flag2) ans1 = ans1 + 1;
} else {
for (int k=arr2.length-1; k>1; k-=2) {
ans1 = arr2[k] * arr2[k-1];
}
ans1 = ans1 + arr2[0];
}
return ans + ans1;
}

Related

What is the minimum number of adjacent swaps needed to segregate a list of 0s and 1s?

I am trying to solve a Data Structures and Algorithms problem, which states that given a group of 1s and 0s, group the digits such that all 0s are together and all 1s are together. What is the minimum number of swaps required to accomplish this if one can only swap two adjacent elements? It does not matter which group is at what end.
Eg:
[0,1,0,1] = [0,0,1,1] 1 swaps
[1,1,1,1,0,1,0] = [1,1,1,1,1,0,0] 1 swaps
[1, 0, 1, 0, 0, 0, 0, 1] = = [1,1,1,0,0,0,0,0] 6 swaps
Note that this is different from the questions asked here:
Find the minimum number of swaps required such that all the 0s and all the 1s are together
I am not sorting the array, I am just trying to group all the 0s and all the 1s together and it does not matter which is at which end.
I really have no clue where to even start. Can someone help me?
Let's focus on zeroes. Each swap moves a single zero a single position closer to the final order. Then we can find the number of swaps by finding the number of displaced zeroes, and the severity of the displacement.
Let's start by assuming that the zeroes end up at the start of the array. We'll keep track of two things: count_of_ones, and displacement, both initialized to zero. Each time we find a 1, we increment count_of_ones. Each time we find a 0, we increase displacement by count_of_ones.
Then we do this in the other direction. Both ways are linear, so this is linear.
E.g. 1010001
1: count_of_ones: 0 -> 1
0: displacement: 0 -> 1
1: count_of_ones: 1 -> 2
0: displacement: 1 -> 3
0: displacement: 3 -> 5
0: displacement: 5 -> 7
1: count_of_ones: 2 -> 3
The answer for this direction is the final displacement, or 7. Going the other way we get 5. Final answer is 5.
In fact, the sum of the final displacements (starting vs ending with all zeroes) will always equal num_zeroes * num_ones. This halves the work (though it's still linear).
From the comments it seems some people didn't understand my answer. Here's a Ruby implementation to make things clearer.
def find_min_swaps(arr)
count_of_ones = 0
displacement = 0
arr.each do |v|
count_of_ones += 1 if v == 1
displacement += count_of_ones if v == 0
end
count_of_zeroes = arr.length - count_of_ones
reverse_displacement = count_of_ones * count_of_zeroes - displacement
return [displacement, reverse_displacement].min
end
The zeroes end up on the left if displacement < reverse_displacement, either if they're equal, or the right if displacement > reverse_displacement.
Let SUM0 be the sum of the (0-based) indexes of all the zeros, and let SUM1 be the sum of the indexes of all the ones. Every time you swap 10 -> 01, SUM0 goes down by one, and SUM1 goes up by one. They go the other way when you swap 01 -> 10.
Lets say you have N0 zeros and N1 ones. If the zeros were packed together at the start of the array, then you would have SUM0 = N0*(N0-1)/2. That's the smallest SUM0 you can have.
Since a single adjacent swap can reduce SUM0 by exactly one, it takes exactly SUM0 - N0*(N0-1)/2 swaps to pack the zeros together at the front. Similarly, it takes SUM1 - N1*(N1-1)/2 swaps to pack the ones together at the front.
Your answer is the smaller of these numbers: min( SUM0 - N0*(N0-1)/2 , SUM1 - N1*(N1-1)/2 )
Those values are all easy to calculate in linear time.
Simple approach using Bubble Sort, which takes O(n2), would be this:
public class MainClass {
public static void main(String[] args) {
int[] arr = new int[]{1, 0, 0, 0, 0, 0, 0, 1, 0};
int minSwaps = minimumSwaps(arr);
System.out.println("Minimum swaps required: " + minSwaps);
}
public static int minimumSwaps(int[] array) {
int[] arr1 = array.clone(), arr2 = array.clone();
int swapsForRight = 0, swapsForLeft = 0;
boolean sorted = false;
while (!sorted) {
sorted = true;
for (int i = 0; i < arr1.length - 1; i++) {
if (arr1[i + 1] < arr1[i]) {
int temp = arr1[i + 1];
arr1[i + 1] = arr1[i];
arr1[i] = temp;
sorted = false;
swapsForRight++;
}
}
}
sorted = false;
while (!sorted) {
sorted = true;
for (int i = 0; i > arr2.length - 1; i++) {
if (arr2[i + 1] < arr2[i]) {
int temp = arr2[i + 1];
arr2[i + 1] = arr2[i];
arr2[i] = temp;
sorted = false;
swapsForLeft++;
}
}
}
return swapsForLeft > swapsForRight ? swapsForRight : swapsForLeft;
}
}

How can we output the indices j and k that identify the maximum subarray

Maximum Subarray Problem
Given an array of n integers, find the subarray, A[j:k] that maximizes the sum as
requirement :
How can we output the indices j and k that
identify the maximum subarray A[j : k]
Please help me out
thanks
You could simply use the most popular algorithm for this, Kadanes Algorithm.
As the algorithm states, I assume a non-empty array passed to it. Then I simply track the indices where the maximum sum begins and ends using two variables, prev and curr
int maxsubarray(int arr[])
{
int maxsofar = arr[0], sum = arr[0], prev = 0, curr = 0;
for i = 1 to arr.size
//number greater than the addition of sums
if(nums[i] > sum + nums[i]) prev = i;
//maximum sum till this point in the array
sum = max(nums[i], sum + nums[i])
// if this is better than what we have so far
if(sum > maxsofar)
//store this sum and the array value
maxsofar = sum
curr = i
print "start index of sum:", prev
print "end index of sum:", curr
// return the maximum value also found so far
return maxsofar;
}
The first solution that came to my mind instantly was: Instead of storing a single value in M, you can use an object like below:
struct M {
float sum,
int start_index,
int end_index
}
Now change your algorithm as below to work with M object:
Algorithm MaxSubFastest2(A):
M[0] = {0, 1, 0}
for t in 1 to n do:
if M[t-1]+A[t] > 0:
M[t] = {M[t-1]+A[t], M[t-1].start_index, M[t-1].end_index+1}
else:
M[t] = {0, 1, 0}
m = 0
start_index = 0
end_index = 0
for t in 1 to n do:
if M[t].sum > m:
m = M[t].sum
start_index = M[t].start_index
end_index = M[t].end_index
if start_index <= end_index:
subarray exists => return m, start_index, end_index
subarray does not exist => error
This algorithm has the same time complexity as above, but will use extra memory.
A more memory optimized version is here:
Algorithm MaxSubFastest3(A):
max_so_far = 0
max_ending_here = 0
start =0
end = 0
s=0
for i in 1 to n:
max_ending_here += A[i]
if max_so_far < max_ending_here:
max_so_far = max_ending_here
start = s
end = i
if max_ending_here < 0:
max_ending_here = 0
s = i + 1
output max_so_far, start, end
This takes up same time and memory as the one in question.
You can find other variations of the same algorithm here.
Plus, I notice that the algorithm you've given in the question will always produce 0 as maximum sum for a list full of -ve numbers. I wonder if that is the expected behavior..

Replace operators of equation, so that the sum is equal to zero

I'm given the equation like this one:
n = 7
1 + 1 - 4 - 4 - 4 - 2 - 2
How can I optimally replace operators, so that the sum of the equation is equal to zero, or print  -1. I think of one algorithm, but it is not optimal. I have an idea to bruteforce all cases with complexity O(n*2^n), but (n < 300).
Here is the link of the problem: http://codeforces.com/gym/100989/problem/M.
You can solve this with dynamic programming. Keep a map of all possible partial sums (mapping to the minimum number of changes to reach this sum), and then update it one number at a time,
Here's a concise Python solution:
def signs(nums):
xs = {nums[0]: 0}
for num in nums[1:]:
ys = dict()
for d, k in xs.iteritems():
for cost, n in enumerate([num, -num]):
ys[d+n] = min(ys.get(d+n, 1e100), k+cost)
xs = ys
return xs.get(0, -1)
print signs([1, 1, -4, -4, -4, -2, -2])
In theory this has exponential complexity in the worst case (since the number of partial sums can double at each step). However, if (as here) the given numbers are always (bounded) small ints, then the number of partial sums grows linearly, and the program works in O(n^2) time.
A somewhat more optimised version uses a sorted array of (subtotal, cost) instead of a dict. One can discard partial sums that are too large or too small (making it impossible to end up at 0 assuming all of the remaining elements are between -300 and +300). This runs approximately twice as fast, and is a more natural implementation to port to a lower-level language than Python for maximum speed.
def merge(xs, num):
i = j = 0
ci = 0 if num >= 0 else 1
cj = 0 if num < 0 else 1
num = abs(num)
while j < len(xs):
if xs[i][0] + num < xs[j][0] - num:
yield (xs[i][0] + num, xs[i][1] + ci)
i += 1
elif xs[i][0] + num > xs[j][0] - num:
yield (xs[j][0] - num, xs[j][1] + cj)
j += 1
else:
yield (xs[i][0] + num, min(xs[i][1] + ci, xs[j][1] + cj))
i += 1
j += 1
while i < len(xs):
yield (xs[i][0] + num, xs[i][1] + ci)
i += 1
def signs2(nums):
xs = [(nums[0], 0)]
for i in xrange(1, len(nums)):
limit = (len(nums) - 1 - i) * 300
xs = [x for x in merge(xs, nums[i]) if -limit <= x[0] <= limit]
for x, c in xs:
if x == 0: return c
return -1
print signs2([1, 1, -4, -4, -4, -2, -2])
Here is the implementation in C++:
unordered_map <int, int> M, U;
unordered_map<int, int>::iterator it;
int a[] = {1, -1, 4, -4};
int solve() {
for(int i = 0; i < n; ++i) {
if(i == 0) M[a[i]] = 1;
else {
vector <pair <int, int>> vi;
for(it = M.begin(); it != M.end(); ++it) {
int k = it->first, d = it->second;
vi.push_back({k + a[i], d});
vi.push_back({k - a[i], d + 1});
}
for(int j = 0; j < vi.size(); ++j) M[vi[j].first] = MAXN;
for(int j = 0; j < vi.size(); ++j) {
M[vi[j].first] = min(M[vi[j].first], vi[j].second);
}
}
}
return (M[0] == 0 ? -1 : M[0] - 1);
}
What I can think of:
You calculate the original equation. This results in -14.
Now you sort the numbers (taking into account their + or -)
When the equation results in a negative number, you look for the largest numbers to fix the equation. When a number is too large, you skip it.
orig_eq = -14
After sorting:
-4, -4, -4, -2, -2, 1, 1
You loop over this and select each number if the equation orig_eq - current number is closer to zero.
This way you can select each number to change the sign of

maximum subarray of an array with integers [duplicate]

This question already has answers here:
Maximum sum sublist?
(13 answers)
Closed 8 years ago.
In an interview one of my friends was asked to find the subarray of an array with maximum sum, this my solution to the problem , how can I improve the solution make it more optimal , should i rather consider doing in a recursive fashion ?
def get_max_sum_subset(x):
max_subset_sum = 0
max_subset_i = 0
max_subset_j = 0
for i in range(0,len(x)+1):
for j in range(i+1,len(x)+1):
current_sum = sum(x[i:j])
if current_sum > max_subset_sum:
max_subset_sum = current_sum
max_subset_i = i
max_subset_j = j
return max_subset_sum,max_subset_i,max_subset_j
Your solution is O(n^2). The optimal solution is linear. It works so that you scan the array from left to right, taking note of the best sum and the current sum:
def get_max_sum_subset(x):
bestSoFar = 0
bestNow = 0
bestStartIndexSoFar = -1
bestStopIndexSoFar = -1
bestStartIndexNow = -1
for i in xrange(len(x)):
value = bestNow + x[i]
if value > 0:
if bestNow == 0:
bestStartIndexNow = i
bestNow = value
else:
bestNow = 0
if bestNow > bestSoFar:
bestSoFar = bestNow
bestStopIndexSoFar = i
bestStartIndexSoFar = bestStartIndexNow
return bestSoFar, bestStartIndexSoFar, bestStopIndexSoFar
This problem was also discussed thourougly in Programming Pearls: Algorithm Design Techniques (highly recommended). There you can also find a recursive solution, which is not optimal (O(n log n)), but better than O(n^2).
This is a well-known problem that displays overlapping optimal substructure, which suggests a dynamic programming (DP) solution. Although DP solutions are usually quite tricky (I think so at least!), this one is a great example to get introduced to the whole concept.
The first thing to note is that the maximal subarray (which must be a contiguous portion of the given array A) ending at position j either consists of the maximimal subarray ending at position j-1 plus A[j], or is empty (this only occurs if A[j] < 0). In other words, we are asking whether the element A[j] is contributing positively to the current maximum sum ending at position j-1. If yes, include it in the maximal subarray so far; if not, don't. Thus, from solving smaller subproblems that overlap we can build up an optimal solution.
The sum of the maximal subarray ending at position j can then be given recursively by the following relation:
sum[0] = max(0, A[0])
sum[j] = max(0, sum[j-1] + A[j])
We can build up these answers in a bottom-up fashion by scanning A from left to right. We update sum[j] as we consider A[j]. We can keep track of the overall maximum value and the location of the maximal subarray through this process as well. Here is a quick solution I wrote up in Ruby:
def max_subarray(a)
sum = [0]
max, head, tail = sum[0], -1, -1
cur_head = 0
(0...a.size).each do |j|
# base case included below since sum[-1] = sum[0]
sum[j] = [0, sum[j-1] + a[j]].max
cur_head = j if sum[j-1] == 0
if sum[j] > max
max, head, tail = sum[j], cur_head, j
end
end
return max, head, tail
end
Take a look at my gist if you'd like to test this for yourself.
This is clearly a linear O(N) algorithm since only one pass through the list is required. Hope this helps!
let n - elements count, a(i) - your array f(i) - maximum sum of subarray that ends at position i (minimum length is 1). Then:
f(0) = a(i);
f(i) = max(f(i-1), 0) + a(i); //f(i-1) when we continue subarray, or 0 - when start at i position
max(0, f(1), f(2), ... , f(n-1)) - the answer
A much better solution approach can be derived by thinking about what conditions must hold for a maximum-sum sub-array: the first item on either end that is not included (if any) must be negative and the last item on either end that is included must be non-negative. You don't need to consider any other end points for the sub-array except where these changes occur in the original data.
There is a short video from MIT that helps you understand this dynamic programming problem.
http://people.csail.mit.edu/bdean/6.046/dp/
Click on the first link under the 'problems' section and you will see it.
Here is a simple O(N) algorithm from http://en.wikipedia.org/wiki/Maximum_subarray_problem
int maxsofar=0;
int maxendinghere=0;
for i=[0 n] {
maxendinghere=max(maxendinghere+x[i],0);
maxsofar=max(maxsofar,maxendinghere);
}
Unless I'm missing something important, if they are positive integers the subset would include the whole array, if they're integers, it would include only positive integers. Is there another constraint there?
Java solution:
Does not work for an array with all negatives.
public static int[] maxsubarray(int[] array) {
//empty array check
if (array.length == 0){
return new int[]{};
}
int max = 0;
int maxsofar = 0;
//indices
int maxsofarstart = 0;
int maxsofarend = 0;
int maxstartindex = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] > 0) {
if (max == 0) {
maxstartindex = i;
}
max = max + array[i];
if (max > maxsofar) {
maxsofar = max;
maxsofarstart = maxstartindex;
maxsofarend = i;
}
} else {
max = 0;
}
}
return Arrays.copyOfRange(array, maxsofarstart, maxsofarend + 1);
}
here is one of most well-expained, tested, working solution - http://rerun.me/blog/2012/08/30/maximum-continuous-subarray-problem-kandanes-algorithm/
package me.rerun;
public class Kadane {
public static void main(String[] args) {
int[] intArr={3, -1, -1, -1, -1, -1, 2, 0, 0, 0 };
//int[] intArr = {-1, 3, -5, 4, 6, -1, 2, -7, 13, -3};
//int[] intArr={-6,-2,-3,-4,-1,-5,-5};
findMaxSubArray(intArr);
}
public static void findMaxSubArray(int[] inputArray){
int maxStartIndex=0;
int maxEndIndex=0;
int maxSum = Integer.MIN_VALUE;
int cumulativeSum= 0;
int maxStartIndexUntilNow=0;
for (int currentIndex = 0; currentIndex < inputArray.length; currentIndex++) {
int eachArrayItem = inputArray[currentIndex];
cumulativeSum+=eachArrayItem;
if(cumulativeSum>maxSum){
maxSum = cumulativeSum;
maxStartIndex=maxStartIndexUntilNow;
maxEndIndex = currentIndex;
}
else if (cumulativeSum<0){
maxStartIndexUntilNow=currentIndex+1;
cumulativeSum=0;
}
}
System.out.println("Max sum : "+maxSum);
System.out.println("Max start index : "+maxStartIndex);
System.out.println("Max end index : "+maxEndIndex);
}
}
This is the correct Java Code which will handle scenarios including all negative numbers.
public static long[] leftToISumMaximize(int N, long[] D) {
long[] result = new long[N];
result[0] = D[0];
long currMax = D[0];
for (int i = 1; i < N; i++) {
currMax = Math.max(D[i], currMax + D[i]);
result[i] = Math.max(result[i - 1], currMax);
}
return result;
}
Not sure but Accepted Solution didn't for work me for all the scenarios (May be I misunderstood it)
So I did small modification, instead of
if(value > 0)
I changed it yo
if(value > bestNow)
.....(I wrote it in Scala)
And it is working for the all scenarios
def findMaxSubArray(list: List[Int]): (Int, Int, Int) = {
var (bestNow,bestSoFar) = (0, 0)
var ( startIndexNow, startIndexSoFar, endIndex) = (-1, -1, -1)
for (i <- 0 until list.length) {
var value = bestNow + list(i)
if (value > bestNow) {
if (bestNow == 0)
startIndexNow = i
bestNow = value
} else
bestNow = 0
if (bestNow > bestSoFar) {
bestSoFar = bestNow
startIndexSoFar = startIndexNow
endIndex = i
}
}
return (bestSoFar, startIndexSoFar, endIndex)
}
def main(args: Array[String]) {
println(findMaxSubArray(List(3, -1, 5, 3, -6, -9, 6, 1)).toString)
println(findMaxSubArray(List(3, -1, 5, 3, -6, -9, 6, 3)).toString)
println(findMaxSubArray(List(20, -1, 5, 3, -6, -9, 6)).toString)
}
Output.....
(max =8, start=2, end=3)
(max=9, start=6, end=7)
(max=20, start=0, end= 0)
I have made a function for a little more general problem:
Find maximum sum subarray (meaning its bounds and sum, not only the sum)
If two subarrays have equal sums then pick the shorter one
If two equally long subarrays have equal sums then pick the one that appears first.
Function is based on Kadane's algorithm and it runs in O(n) time. Basically, this is it:
function MaxSumSubarray(a, n, start out, len out)
-- a - Array
-- n - Length of the array
-- start - On output starting position of largest subarray
-- len - On output length of largest subarray
-- Returns sum of the largest subarray
begin
start = 0
len = 1
int sum = a[0]
curStart = 0
curLen = 1
curSum = a[0]
for i = 2 to n
begin
if a[i] >= curSum + a[i] then
begin
curStart = i
curLen = 1
curSum = a[i]
end
else
begin
curLen = curLen + 1
curSum = curSum + a[i]
end
if (curSum > sum) OR
(curSum = sum AND curLen < len) OR
(curSum = sum AND curLen = len AND curStart < start) then
begin
start = curStart
len = curLen
sum = curSum
end
end
return sum
end
I've uploaded the whole solution in C#, with analysis and examples, in this article: Maximum Sum Subarray

Sub array that produces a given sum and product

Given an array of length N. How will you find the minimum length
contiguous sub-array of whose sum is S and whose product is P.
For eg 5 6 1 4 6 2 9 7 for S = 17, Ans = [6, 2, 9] for P = 24, Ans = [4 6].
Just go from left to right, and sum all the numbers, if the sum > S, then throw away left ones.
import java.util.Arrays;
public class test {
public static void main (String[] args) {
int[] array = {5, 6, 1, 4, 6, 2, 9, 7};
int length = array.length;
int S = 17;
int sum = 0; // current sum of sub array, assume all positive
int start = 0; // current start of sub array
int minLength = array.length + 1; // length of minimum sub array found
int minStart = 0; // start of of minimum sub array found
for (int index = 0; index < length; index++) {
sum = sum + array[index];
// Find by add to right
if (sum == S && index - start + 1 < minLength) {
minLength = index - start + 1;
minStart = start;
}
while (sum >= S) {
sum = sum - array[start];
start++;
// Find by minus from left
if (sum == S && index - start + 1 < minLength) {
minLength = index - start + 1;
minStart = start;
}
}
}
// Found
if (minLength != length + 1) {
System.out.println(Arrays.toString(Arrays.copyOfRange(array, minStart, minStart + minLength)));
}
}
}
For your example, I think it is OR.
Product is nothing different from sum, except for calculation.
pseudocode:
subStart = 0;
Sum = 0
for (i = 0; i< array.Length; i++)
Sum = Sum + array[i];
if (Sum < targetSum) continue;
if (Sum == targetSum) result = min(result, i - subStart +1);
while (Sum >= targetSum)
Sum = Sum - array[subStart];
subStart++;
I think that'll find the result with one pass through the array. There's a bit of detail missing there in the result value. Needs a bit more complexity there to be able to return the actual subarray if needed.
To find the Product sub-array just substitute multiplication/division for addition/subtraction in the above algorithm
Put two indices on the array. Lets call them i and j. Initially j = 1 and i =0. If the product between i and j is less than P, increment j. If it is greater than P, increment i. If we get something equal to p, sum up the elements (instead of summing up everytime, maintain an array where S(i) is the sum of everything to the left of it. Compute sum from i to j as S(i) - S(j)) and see whether you get S. Stop when j falls out of the array length.
This is O(n).
You can use a hashmap to find the answer for product in O(N) time with extra space.

Resources