maximum sum of subsequence - algorithm

Given an integer array, find the maximum sum of subsequence where the subsequence contains no element at adjacent positions.
Input: { 1, 2, 9, 4, 5, 0, 4, 11, 6 }
Output: The maximum sum is 26
The maximum sum is formed by subsequence { 1, 9, 5, 11 }
My below code is working fine .helper2 method is same as findMaxSumSubsequence but with memoisation.Both these methods call themselves recursively exploring all subsets i.e take the element at ith pos or not take the element at ith position.
private int findMaxSumSubsequence(int[] arr ,int i ,boolean flag) {
if( i>=arr.length)
return 0;
int incAns=0;
if(!flag)
{
incAns=findMaxSumSubsequence(arr,i+1,true) + arr[i];
}
int exAns=findMaxSumSubsequence(arr,i+1,false) ;
return Math.max(incAns, exAns);
But when i try to memoise the code I get the wrong answer for
helper2(nums,0,false) //method call
nums={1,2} after memoisation i get answer as 1 .Correct answer is 2.
int[] memo is initialised with -1 .
int[] memo = new int[101];
private int helper2(int[] arr ,int i ,boolean flag) {
if( i>=arr.length)
return memo[i]=0;
if(memo[i]!=-1)
return memo[i];
int incAns=0;
if(!flag)
{
incAns=helper2(arr,i+1,true) + arr[i];
}
int exAns=helper2(arr,i+1,false) ;
memo[i]= Math.max(incAns, exAns);
return Math.max(incAns, exAns);

You are missing the second memoization parameter 'flag', that's why you have a wrong answer, it should be:
int[][] memo = new int[101][2];
instead of
int[] memo = new int[101];
code:
int[][] memo = new int[101][2];
int [] arr;
private int helper2(int i ,boolean flag) {
if (i >= arr.length)
return 0;
if (memo[i][flag? 1 : 0] != -1) return memo[i][flag ? 1 : 0];
int incAns = 0;
if (!flag) {
incAns = helper2( i + 1, true) + arr[i];
}
int exAns = helper2( i + 1, false);
return memo[i][flag? 1 : 0] = Math.max(incAns, exAns);
}
public static void main(String[] args) {
arr = new int[]{1, 2};
for(int i = 0; i < 100; i++) Arrays.fill(memo[i], -1);
out.println(helper2(0, false));
}
Also no need to add the array as a parameter in the recursive function because it's static and don't change, otherwise you will get Memory Limit Exceeded.

Related

Competitive programming - Prepare the perfect curry with ingredients P, Q, and R

Recently i got a competetive programming task which i couldn't manage to complete. Just curious to know the best solution for the problem
"A" is a zero-indexed array of N integers.
Elements of A are integers within the range [−99,999,999 to 99,999,999]
The 'curry' is a string consisting of N characters such that each character is either 'P', 'Q' or 'R' and the
corresponding index of the array is the weight of each ingredient.
The curry is perfect if the sum of the total weights of 'P', 'Q' and 'R' is equal.
write a function
makeCurry(Array)
such that, given a zero-indexed array Array consisting of N integers, returns the perfect curry of this array.
The function should return the string "noLuck" if no perfect curry exists for that Array.
For example, given array Array such that
A[0] = 3 A[1] = 7 A[2] = 2 A[3] = 5 A[4] = 4
the function may return "PQRRP", as explained above. Given array A such that
A[0] = 3 A[1] = 6 A[2] = 9
the function should return "noLuck".
The approach i tried was this
import collections
class GetPerfectCurry(object):
def __init__(self):
self.curry = ''
self.curry_stats = collections.Counter({'P': 0, 'Q': 0, 'R': 0})
pass
def get_perfect_curry(self, A):
if len(A) == 0:
return "noLuck"
A.sort(reverse=True)
for i, ele in enumerate(A):
self.check_which_key_to_add_new_element_and_add_element(ele)
if self.curry_stats['P'] == self.curry_stats['Q'] == self.curry_stats['R']:
return self.curry
else:
return "noLuck"
def check_which_key_to_add_new_element_and_add_element(self, val):
# get the maximum current value
# check if addition of new value with any of the other two key equals the max value
# if yes then add that value and append the key in the curry string
current_max_key = max(self.curry_stats, key=self.curry_stats.get)
check_for_equality = False
key_to_append = None
for key, ele in enumerate(self.curry_stats):
if ele != current_max_key:
if self.curry_stats[ele] + val == self.curry_stats[current_max_key]:
check_for_equality = True
key_to_append = ele
if check_for_equality:
self.curry_stats.update(str(key_to_append) * val)
self.curry += str(key_to_append)
pass
else:
# if no value addition equals the current max
# then find the current lowest value and add it to that key
current_lowest_key = min(self.curry_stats, key=self.curry_stats.get)
self.curry_stats.update(str(current_lowest_key)*val)
self.curry += str(current_lowest_key)
if __name__ == '__main__':
perfect_curry = GetPerfectCurry()
A = [3, 7, 2, 5, 4]
# A = [3, 6, 9]
# A = [2, 9, 6, 3, 7]
res = perfect_curry.get_perfect_curry(A)
print(res)
But it was incorrect. Scratching my head for the past four hours for the best solution for this problem
A possible algorithm is as follows:
Sum the weights. If it's not a multiple of 3, no luck. If it is, divide by 3 to get the target.
Find subsets of A that add up to target. For such subsets, remove it and you get B. Find a subset of B that adds up to target.
Here's a Java implementation (I'm not a Python guy, sorry):
import java.util.Arrays;
public class Main
{
// Test if selected elements add up to target
static boolean check(int[] a, int selection, int target)
{
int sum = 0;
for(int i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 1)
sum += a[i];
}
return sum==target;
}
// Remove the selected elements
static int[] exclude(int[] a, int selection)
{
int[] res = new int[a.length];
int j = 0;
for(int i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 0)
res[j++] = a[i];
}
return Arrays.copyOf(res, j);
}
static String getCurry(int[] a)
{
int sum = 0;
for(int x : a)
sum += x;
if(sum%3 > 0)
return "noLuck";
int target = sum/3;
int max1 = 1<<a.length; // 2^length
for(int i=0;i<max1;i++)
{
if(check(a, i, target))
{
int[] b = exclude(a, i);
int max2 = 1<<b.length; // 2^length
for(int j=0;j<max2;j++)
{
if(check(b, j, target))
return formatSolution(i, j, a.length);
}
}
}
return "noLuck";
}
static String formatSolution(int p, int q, int len)
{
char[] res = new char[len];
Arrays.fill(res, 'R');
int j = 0;
for(int i=0;i<len;i++)
{
if(((p>>i) & 1) == 1)
res[i] = 'P';
else
{
if(((q>>j) & 1) == 1)
res[i] = 'Q';
j++;
}
}
return new String(res);
}
public static void main(String[] args)
{
// int[] a = new int[]{3, 7, 2, 5, 4};
// int[] a = new int[]{1, 1, 2, -1};
int[] a = new int[]{5, 4, 3, 3, 3, 3, 3, 3};
System.out.println(getCurry(a));
}
}
You can test it here.
Hereafter so many years I'm writing code for js for needed people. (TBH I took the ref of the accepted answer)
As he mentioned, A possible algorithm is as follows:
Sum the weights. If it's not a multiple of 3, no luck. If it is, divide by 3 to get the target.
Find subsets of A that add up to target. For such subsets, remove it and you get B. Find a subset of B that adds up to target.
// Test if selected elements add up to target
function check(a, selection, target)
{
let sum = 0;
for(let i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 1)
sum += a[i];
}
return sum==target;
}
// Remove the selected elements
function exclude(a, selection)
{
let res = [a.length];
let j = 0;
for(let i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 0)
res[j++] = a[i];
}
return res
}
function getCurry(a)
{
let sum = a.reduce((accumulator, currentValue) => accumulator + currentValue);
if(sum%3 > 0)
return "noLuck";
let target = sum/3;
let max1 = 1<<a.length; // 2^length
for(let i=0;i<max1;i++)
{
if(check(a, i, target))
{
let b = exclude(a, i);
let max2 = 1<<b.length; // 2^length
for(let j=0;j<max2;j++)
{
if(check(b, j, target))
return formatSolution(i, j, a.length);
}
}
}
return "noLuck";
}
function formatSolution(p, q, len)
{
let res = new Array(len)
res.fill('R')
let j = 0;
for(let i=0;i<len;i++)
{
if(((p>>i) & 1) == 1)
res[i] = 'P';
else
{
if(((q>>j) & 1) == 1)
res[i] = 'Q';
j++;
}
}
return new String(res);
}
// let a = [3, 7, 2, 5, 4]
// let a = [1, 1, 2, -1]
let a = [5, 4, 3, 3, 3, 3, 3, 3]
getCurry(a)

K-way merge operation for merge sort

I have k sorted arrays, each with n elements, and need to combine them into a single sorted array of k*n elements.
How do I implement the merging procedure for merge sort, starting with the first two and the next one and so on?
This is what I have so far.
// implementing function to merge arrays (merge procedure for merge sort)
public int[] merge(int[][] array){
int k = array.length;
int n = array[0].length;
// final merged array
int[] mergedArray = new int[k*n];
return mergedArray;
}
public static void main(String[]args){
Merge obj = new Merge();
int[][] data= new int[][]{{2, 9, 15, 20},
{6, 8, 9, 19},
{5, 10, 18, 22},
{8, 12, 15, 26}};
int[] mergedArrayTest = obj.merge(data);
//printArray(mergedArrayTest);
}
Instead of merging the sub-arrays two at a time, you can merge all k at once.
Make an array of indices into each sub-array. Initially each index is zero.
On each one of k*n iterations to fill the merged array, consider each sub-array's value at its respective index and remember the minimum value. (Skip an index if it has already reached the end of the sub-array.)
Increment the index that pointed to the minimum value.
This will do it:
// k-way merge operation
public int[] merge(int[][] array){
int k = array.length;
int n = array[0].length;
int[] mergedArray = new int[k*n];
int[] indices = new int[k];
for (int i = 0; i < mergedArray.length; ++i) {
int bestValue = -1, bestIndex = -1;
for (int j = 0; j < indices.length; ++j) {
int index = indices[j];
if (index < n && (bestValue == -1 || array[j][index] < bestValue)) {
bestValue = array[j][index];
bestIndex = j;
}
}
mergedArray[i] = bestValue;
indices[bestIndex] += 1;
}
return mergedArray;
}
You can make this approach somewhat more efficient by removing indices that have reached the end of their sub-array. However, that still leaves the running time in O(nk2) because O(k) indices are scanned nk times.
We can make an asymptotic improvement in running time by storing the indices in a min-heap that uses the value at each index as the key. With k indices, the size of the heap never exceeds k. In each of nk iterations, we pop the heap and push at most one element back on. These heap operations each cost O(log k), so the total running time is O(nk log k).
import java.lang.*;
import java.util.*;
import java.io.*;
class Candidate {
int id, index, value;
Candidate(int id, int index, int value) {
this.id = id;
this.index = index;
this.value = value;
}
}
class Heap {
ArrayList<Candidate> stack = new ArrayList<Candidate>();
void push(Candidate current) {
// Add to last position in heap.
stack.add(current);
// Bubble up.
int n = stack.size(),
pos = n - 1;
while (pos != 0) {
int parent = (pos - 1) / 2;
if (stack.get(parent).value <= current.value) {
return;
}
stack.set(pos, stack.get(parent));
stack.set(parent, current);
}
}
Candidate pop() {
// Get top of heap.
if (stack.size() == 0) {
return null;
}
Candidate result = stack.get(0);
int n = stack.size();
if (n == 1) {
stack.remove(0);
return result;
}
// Swap last element to top.
stack.set(0, stack.get(--n));
Candidate current = stack.get(0);
stack.remove(n);
// Bubble down.
int pos = 0;
while (true) {
int left = 2 * pos + 1;
if (left >= n) {
return result;
}
int right = left + 1,
swapTo = -1;
if (current.value <= stack.get(left).value) {
if (right == n || current.value <= stack.get(right).value) {
return result;
}
swapTo = right;
} else {
if (right != n && stack.get(left).value > stack.get(right).value) {
swapTo = right;
} else {
swapTo = left;
}
}
stack.set(pos, stack.get(swapTo));
stack.set(swapTo, current);
pos = swapTo;
}
}
}
public class Merge {
// k-way merge
public int[] merge(int[][] array){
int k = array.length;
int n = array[0].length;
int[] mergedArray = new int[k*n];
// Initialize heap with subarray number, index, and value.
Heap indexHeap = new Heap();
for (int i = 0; i < k; ++i) {
indexHeap.push(new Candidate(i, 0, array[i][0]));
}
for (int i = 0; i < mergedArray.length; ++i) {
// Get the minimum value from the heap and augment the merged array.
Candidate best = indexHeap.pop();
mergedArray[i] = best.value;
// Increment the index. If it's still valid, push it back onto the heap.
if (++best.index < array[best.id].length) {
best.value = array[best.id][best.index];
indexHeap.push(best);
}
}
// Print out the merged array for testing purposes.
for (int i = 0; i < mergedArray.length; ++i) {
System.out.print(mergedArray[i] + " ");
}
System.out.println();
return mergedArray;
}
public static void main(String[]args){
Merge merge = new Merge();
int[][] data= new int[][]{{2, 9, 15, 20},
{6, 8, 9, 19},
{5, 10, 18, 22},
{8, 12, 15, 26}};
int[] mergedArrayTest = merge.merge(data);
}
}

Find all M-length sets of positive integers that sum to N

The problem I'm trying to solve is how do we find all the integer sets [a1, a2, ... ,am] so that
a1 + a2 + ... + am = N
and with the constraint ai >= 1
For example if M = 4, and N = 7 there are three answers
[1,1,1,4]
[1,1,2,3]
[1,2,2,2]
Since you have to print all the sets that sum to N. You can employ a complete search algorithm using recursion. In the following code, M is the number of numbers in the set and N is the sum required.
int M;
int N;
void run(){
M = 4;
N = 7;
int[] arr = new int[M];
print(arr, 0, N, 1);
}
// req holds the required sum for the numbers in the array from arr[from]
// to arr[M-1].
// "last" holds the last value that we had put in the array.
// The first call to the array will be with last=1.
void print(int[] arr, int from, int req, int last){
// Reached the end of the array and sum required 0.
if(from==M && req==0){
System.out.println(Arrays.toString(arr));
return;
}
// Either reached the end of the array but sum is not equal to N
// Or if we have not reached the end of the array but sum has already
// become more than or equal to N.
if(from==M || req<=0){
return;
}
for(int i=last; i<=req; i++){
arr[from] = i;
print(arr, from+1, req-i, i);
}
}
Output for M=4 and N=7:
[1, 1, 1, 4]
[1, 1, 2, 3]
[1, 2, 2, 2]
Output for M=3 and N=10:
[1, 1, 8]
[1, 2, 7]
[1, 3, 6]
[1, 4, 5]
[2, 2, 6]
[2, 3, 5]
[2, 4, 4]
[3, 3, 4]
Answer for the problem in the link, just got accepted.
The idea is simple, assume that we know the maximum value for each section is X, and we want to find a way to divide these cabinets to achieve that , we can greedily divide them as follow:
Starting from first cabinet, iterating through each cabinet, until the total from first to ith cabinet is greater than X. So this is the first section, similarly, we can select other sections. This greedy will always find a solution (if exists).
Finally, we can using binary search to adjust the value of X, decrease X if we can find a way to divide the cabinets, or increase X if we cannot find one.
Here is the code in Java:
public class FairWorkload {
public int getMostWork(int[] folders, int workers) {
int[] data = new int[folders.length];
data[0] = folders[0];
for (int i = 1; i < data.length; i++) {
data[i] = data[i - 1] + folders[i];
}
if (workers == 1) {
return data[data.length - 1];
}
int start = 0;
int end = data[data.length - 1];
int result = Integer.MAX_VALUE;
while (start <= end) {
int mid = (start + end) / 2;
int index = 0;
for (int k = 0; k < workers && index < data.length; k++) {
int less = index > 0 ? data[index - 1] : 0;
int temp = index;
for (int i = index; i < data.length; i++) {
if (data[i] - less <= mid) {
temp = i;
} else {
break;
}
}
// System.out.println(data[temp] - less + " " + mid);
if(data[temp] - less > mid){
index = -1;
break;
}
index = temp + 1;
}
//System.out.println(mid + " " + index);
if (index != data.length) {
start = mid + 1;
} else {
result = Math.min(result, mid);
end = mid - 1;
}
}
return result;
}
public static void main(String[] args) {
int[] data = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1000};
System.out.println(new FairWorkload().getMostWork(data, 2));
}
}
One possible solution uses a counting technique, finding the rightmost term that satisfies [i] <= [length-1] - 2, and then flattening out all other terms to the right as much as possible, keeping a[i] <= a[i+1].
import java.util.Arrays;
public class test {
public static void main(String[] args) {
test t = new test();
t.go();
}
private void go() {
int w = 3;
int sum = 10;
int[] terms = new int[w];
for (int i = 0; i < terms.length; i++) {
terms[i] = 1;
}
terms[w-1] = sum - w + 1;
System.out.println(Arrays.toString(terms));
for (int i = right_index(terms); i>=0; i = right_index(terms)) {
terms[i]++;
int a = terms[i];
int overflow = -1;
// balance all the terms to the right
for (int j = i+1; j < terms.length-1; j++) {
overflow += terms[j] - a;
terms[j] = a;
}
terms[terms.length-1] += overflow;
System.out.println(Arrays.toString(terms));
}
}
// find the rightmost index i, where [i] <= [ia.length-1] - 2
private int right_index(int[] ia) {
int max = ia[ia.length-1];
for (int i = ia.length - 1; i >= 0; i--) {
if (ia[i] <= max - 2)
return i;
}
return -1;
}
}

[Interview]Find the max no that can be formed by any permutation of the arrangement of positive integers

Given an array of positive integers, find the max no that can be formed by any permutation of the arrangement. I would like to know if there are any better Data Structures which can allow to give a more elegant solution for problem.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class FindMaximumNumbersFromPermutation {
static class DS implements Comparable<DS> {
int intAtI;
Integer[] actualInt;
public DS(int intAtI, Integer[] actualInt) {
super();
this.intAtI = intAtI;
this.actualInt = actualInt;
}
#Override
public int compareTo(DS o) {
if(intAtI < o.intAtI)
return 1;
else if(intAtI == o.intAtI)
return 0;
else return -1;
}
#Override
public String toString() {
String s="";
for(int i=0;i<actualInt.length;i++)
s= s+actualInt[i];
return s;
}
}
public static void main(String[] args)
{
int[] arr = {21,9,23};
List<Integer[]> list = new ArrayList<Integer[]>();
int maxLength= 0;
for(int i=0;i<arr.length;i++)
{
Integer[] digitsArray = getDigitsArray(arr[i]);
if(digitsArray.length > maxLength)
maxLength = digitsArray.length;
list.add(digitsArray);
}
List<Integer[]> output = new ArrayList<Integer[]>();
for(int currentLength=0;currentLength<=maxLength;currentLength++)
doWork(list, output, currentLength);
for(int i=0;i<output.size();i++)
{
Integer[] temp = output.get(i);
for(int j=0;j<temp.length;j++)
{
System.out.print(temp[j]);
}
}
}
private static void doWork(List<Integer[]> list, List<Integer[]> output,
int currentLength) {
List<DS> dsList = new ArrayList<DS>();
for(int i=0;i<list.size();i++)
{
Integer[] temp = list.get(i);
if(temp.length>currentLength)
{
dsList.add(new DS(temp[currentLength],temp));
}
}
Collections.sort(dsList);
Map<Integer,List<Integer[]>> map = new TreeMap<Integer,List<Integer[]>>();
for(int i=0;i<dsList.size();i++)
{
DS ds = dsList.get(i);
if(!map.containsKey(ds.intAtI))
{
List<Integer[]> l = new ArrayList<Integer[]>();
l.add(ds.actualInt);
map.put(ds.intAtI, l);
}
else
{
List<Integer[]> l = map.get(ds.intAtI);
l.add(ds.actualInt);
map.put(ds.intAtI, l);
}
}
ArrayList<Integer> keys = new ArrayList<Integer>(map.keySet());
for(int i=keys.size()-1;i>=0;i--)
{
Integer key = keys.get(i);
List<Integer[]> l = map.get(key);
if(l.size() ==1)
output.add(l.get(0));
}
}
static Integer[] getDigitsArray(int integer)
{
String s = integer+"";
Integer[] ret = new Integer[s.length()];
for(int i=0;i<s.length();i++)
{
ret[i] = Integer.parseInt(s.charAt(i)+"");
}
return ret;
}
}
The general case (gluing together arbitrary nonnegative integers, not necessarily digits), IMHO, is quite interesting, for instance
[709, 8, 70, 71, 5, 7] -> 8771709705
[31, 34, 30, 3] -> 3433130
[334, 323, 30, 31, 3] -> 33433233130
The idea is the same as H2CO3 mentioned: array sorting,
but the implementation (C#) is different
private static int Compare(int x, int y) {
if (x == y)
return 0;
// Not that good solution (to compare chars), but easy to implement
String Stx = x.ToString(CultureInfo.InvariantCulture);
String Sty = y.ToString(CultureInfo.InvariantCulture);
int n = Stx.Length < Sty.Length ? Stx.Length : Sty.Length;
// Standard lexicographic comparison: 9 > 80, 293 > 2896, 9873 > 986 etc.
for (int i = 0; i < n; ++i)
if (Stx[i] > Sty[i])
return 1;
else if (Stx[i] < Sty[i])
return -1;
// Special case: ab <>= a?
// 70 < 7; 78 > 7 etc
if (Stx.Length > Sty.Length) {
for (int i = n; i < Stx.Length; ++i)
if (Stx[i - 1] > Stx[i])
return -1;
else if (Stx[i - 1] < Stx[i])
return 1;
}
else {
for (int i = n; i < Sty.Length; ++i)
if (Sty[i - 1] > Sty[i])
return 1;
else if (Sty[i - 1] < Sty[i])
return -1;
}
return 0;
}
Then
int[] data = new int[] { 709, 8, 70, 71, 5, 7 };
Array.Sort(data, Compare);
StringBuilder Sb = new StringBuilder();
for (int i = data.Length - 1; i >= 0; --i)
Sb.Append(data[i]);
// 8771709705
String result = Sb.ToString();
Assuming the "positive integers" are the digits (nothing else makes sense to me given this constraint about the permutation), the solution is simple: sort the array of integers, the first digit of the largest number will be the largest one, the second the second largest, etc. E. g., given an array of digits numbers 1 5 7 3, the sorted array is 7 5 3 1, so the largest such number is 7531. Sorting can be done in O(n log n), or even in O(n).
Edit: if numbers are not constrained to be single digits, then extract all the digits from each number, remove duplicates and add them to an array, and do the sorting etc. with that array from now on.
C++ demonstration:
#include <iostream>
#include <map>
#include <sstream>
#include <set>
#define COUNT(a) (sizeof(a) / sizeof((a)[0]))
void add_digits(std::set<int> &digits, int n)
{
if (n == 0) {
digits.insert(0);
} else {
while (n) {
digits.insert(n % 10);
n /= 10;
}
}
}
int main()
{
int nums[] = { 21, 9, 23 };
std::set<int> digits;
for (int i = 0; i < COUNT(nums); i++)
add_digits(digits, nums[i]);
std::cout << "The largest number is ";
for (std::set<int>::reverse_iterator it = digits.rbegin(); it != digits.rend(); it++)
std::cout << *it;
std::cout << std::endl;
return 0;
}
And it works, even with numbers with zeroes in them.
Edit 2: if you don't need the digits to be unique, then use a vector instead of a set:
#include <iostream>
#include <vector>
#define COUNT(a) (sizeof(a) / sizeof((a)[0]))
void add_digits(std::vector<int> &digits, int n)
{
if (n == 0) {
digits.push_back(0);
return;
}
while (n) {
digits.push_back(n % 10);
n /= 10;
}
}
bool intcmp(const int &lhs, const int &rhs)
{
return lhs > rhs;
}
int main()
{
int nums[] = { 21, 9, 23 };
std::vector<int> digits;
for (int i = 0; i < COUNT(nums); i++)
add_digits(digits, nums[i]);
std::sort(digits.begin(), digits.end(), intcmp);
std::cout << "The largest number is ";
for (std::vector<int>::iterator it = digits.begin(); it != digits.end(); it++)
std::cout << *it;
std::cout << std::endl;
return 0;
}
Suppose you have some 1-digit numbers, some 2-digit, 3-digit, ..., r-digit.
Group you numbers into r lists by number of digits, and sort each of these lists. At each step, the number you append will be the largest element of one of these lists, so this will help if the set of numbers is large relative to r.
E.g., [1,2,21,33,94,9, 88] => [9,2,1] and [94, 88, 33, 21]
9 [2,1][94, 88, 33, 21]
994 [2,1][88, 33, 21]
99488 [2,1][33,21]
9948833 [2,1][21]
99488332 [1][21]
9948833221 [1]
99488332211 [] done
Next, you need an efficient way of picking the right number from the numbers at the head of your lists.
Start with the shortest number of digits and go through the numbers at the head of the lists in ascending order of number of digits. Store your current candidate (initially the head of the shortest-digit list). If your current candidate K has k digits, and you're comparing to a number S with s>k digits, consider the first k digits of S. If that is bigger than K then make S your candidate. If that is less than K then skip S.
The only tricky case is if they're equal. Then, compare the two orders the pair could go in and choose the one which goes first in the larger of the two to be your candidate. I believe the choice is arbitrary if they're equal, but haven't convinced myself.

Given an input array find all subarrays with given sum K

Given an input array we can find a single sub-array which sums to K (given) in linear time, by keeping track of sum found so far and the start position. If the current sum becomes greater than the K we keep removing elements from start position until we get current sum <= K.
I found sample code from geeksforgeeks and updated it to return all such possible sets. But the assumption is that the input array consists of only +ve numbers.
bool subArraySum(int arr[], int n, int sum)
{
int curr_sum = 0, start = 0, i;
bool found = false;
for (i = 0; i <= n; i++)
{
while (curr_sum > sum && start < i)
{
curr_sum = curr_sum - arr[start];
start++;
}
if (curr_sum == sum)
{
cout<<"Sum found in b/w indices: "<<start<<" & "<<(i-1)<<"\n";
curr_sum -= arr[start];
start++;
found = true;
}
// Add this element to curr_sum
if (i < n) {
curr_sum = curr_sum + arr[i];
}
}
return found;
}
My question is do we have such a solution for mixed set of numbers too (both positive and negative numbers)?
There is no linear-time algorithm for the case of both positive and negative numbers.
Since you need all sub-arrays which sum to K, time complexity of any algorithm cannot be better than size of the resulting set of sub-arrays. And this size may be quadratic. For example, any sub-array of [K, -K, K, -K, K, -K, ...], starting and ending at positive 'K' has the required sum, and there are N2/8 such sub-arrays.
Still it is possible to get the result in O(N) expected time if O(N) additional space is available.
Compute prefix sum for each element of the array and insert the pair (prefix_sum, index) to a hash map, where prefix_sum is the key and index is the value associated with this key. Search prefix_sum - K in this hash map to get one or several array indexes where the resulting sub-arrays start:
hash_map[0] = [-1]
prefix_sum = 0
for index in range(0 .. N-1):
prefix_sum += array[index]
start_list = hash_map[prefix_sum - K]
for each start_index in start_list:
print start_index+1, index
start_list2 = hash_map[prefix_sum]
start_list2.append(index)
Solution as given by #Evgeny Kluev coded in Java with a little explanation.
public static void main(String[] args) {
int[] INPUT = {5, 6, 1, -2, -4, 3, 1, 5};
printSubarrays(INPUT, 5);
}
private static void printSubarrays(int[] input, int k) {
Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
List<Integer> initial = new ArrayList<Integer>();
initial.add(-1);
map.put(0, initial);
int preSum = 0;
// Loop across all elements of the array
for(int i=0; i< input.length; i++) {
preSum += input[i];
// If point where sum = (preSum - k) is present, it means that between that
// point and this, the sum has to equal k
if(map.containsKey(preSum - k)) { // Subarray found
List<Integer> startIndices = map.get(preSum - k);
for(int start : startIndices) {
System.out.println("Start: "+ (start+1)+ "\tEnd: "+ i);
}
}
List<Integer> newStart = new ArrayList<Integer>();
if(map.containsKey(preSum)) {
newStart = map.get(preSum);
}
newStart.add(i);
map.put(preSum, newStart);
}
}
Quadratic Time: O(n2) in worst case.
private static void findSubArray(int[] is, int N) {
System.out.println("Continuous sub array of " + Arrays.toString(is) + " whose sum is " + N + " is ");
List<Integer> arry = new ArrayList<>(is.length);
for (int i = 0; i < is.length; i++) {
int tempI = is[i];
arry.add(tempI);
for (int j = i + 1; j < is.length; j++) {
if (tempI + is[j] == N) {
arry.add(is[j]);
System.out.println(arry);
} else if (tempI + is[j] < N) {
arry.add(is[j]);
tempI = tempI + is[j];
} else {
arry.clear();
break;
}
}
}
}
public static void main(String[] args) {
findSubArray(new int[] { 42, 15, 12, 8, 6, 32 }, 26);
findSubArray(new int[] { 12, 5, 31, 13, 21, 8 }, 49);
findSubArray(new int[] { 15, 51, 7, 81, 5, 11, 25 }, 41);
}
This problem is very similar to the combination problem solved here: http://introcs.cs.princeton.edu/java/23recursion/Combinations.java.html
Here is my solution:
public static void main(String[] args) {
int [] input = {-10, 0, 5, 10, 15, 20, 30};
int expectedSum = 20;
combination(new SumObj(new int[0]), new SumObj(input), expectedSum);
}
private static void combination(SumObj prefixSumObj, SumObj remainingSumObj, int expectedSum){
if(prefixSumObj.getSum() == expectedSum){
System.out.println(Arrays.toString(prefixSumObj.getElements()));
}
for(int i=0; i< remainingSumObj.getElements().length ; i++){
// prepare new prefix
int [] newPrefixSumInput = new int[prefixSumObj.getElements().length + 1];
System.arraycopy(prefixSumObj.getElements(), 0, newPrefixSumInput, 0, prefixSumObj.getElements().length);
newPrefixSumInput[prefixSumObj.getElements().length] = remainingSumObj.getElements()[i];
SumObj newPrefixSumObj = new SumObj(newPrefixSumInput);
// prepare new remaining
int [] newRemainingSumInput = new int[remainingSumObj.getElements().length - i - 1];
System.arraycopy(remainingSumObj.getElements(), i+1, newRemainingSumInput, 0, remainingSumObj.getElements().length - i - 1);
SumObj newRemainingSumObj = new SumObj(newRemainingSumInput);
combination(newPrefixSumObj, newRemainingSumObj, expectedSum);
}
}
private static class SumObj {
private int[] elements;
private int sum;
public SumObj(int[] elements) {
this.elements = elements;
this.sum = computeSum();
}
public int[] getElements() {
return elements;
}
public int getSum() {
return sum;
}
private int computeSum(){
int tempSum = 0;
for(int i=0; i< elements.length; i++){
tempSum += elements[i];
}
return tempSum;
}
}
Try this code this can work for you:
private static void printSubArrayOfRequiredSum(int[] array, int requiredSum) {
for (int i = 0; i < array.length; i++) {
String str = "[ ";
int sum = 0;
for (int j = i; j < array.length; j++) {
sum = sum + array[j];
str = str + array[j] + ", ";
if (sum == requiredSum) {
System.out.println(" sum : " + sum + " array : " + str
+ "]");
str = "[ ";
sum = 0;
}
}
}
}
Use this method like :
int array[] = { 3, 5, 6, 9, 14, 8, 2, 12, 7, 7 };
printSubArrayOfRequiredSum(array, 14);
Output :
sum : 14 array : [ 3, 5, 6, ]
sum : 14 array : [ 14, ]
sum : 14 array : [ 2, 12, ]
sum : 14 array : [ 7, 7, ]
Solution as given by #Evgeny Kluev coded in c++
#include<bits/stdc++.h>
using namespace std;
int c=0;
// Function to print subarray with sum as given sum
void subArraySum(int arr[], int n, int k)
{
map<int,vector<int>>m1;
m1[0].push_back(-1);
int curr_sum=0;
for(int i=0;i<n;i++){
curr_sum=curr_sum+arr[i];
if(m1.find(curr_sum-k)!=m1.end()){
vector<int>a=m1[curr_sum-k];
c+=m1[curr_sum-k].size();
for(int j=0;j<a.size();j++){ // printing all indexes with sum=k
cout<<a[j]+1<<" "<<i<<endl;
}
}
m1[curr_sum].push_back(i);
}
}
int main()
{
int arr[] = {10,2,0,10,0,10};
int n = sizeof(arr)/sizeof(arr[0]);
int sum = 10;
subArraySum(arr, n, sum);
cout<<c<<endl; //count of subarrays with given sum
return 0;
}
class Solution
{
//Function to find a continuous sub-array which adds up to a given number.
static ArrayList<Integer> subarraySum(int[] arr, int n, int s)
{
ArrayList<Integer> res=new ArrayList<>();
int i=0,j=0,sum=0;
sum=sum+arr[i];
if(s==0){
res.add(-1);
return res;
}
while(true)
{
if(sum<s)
{
j=j+1;
if(j>=n || i>=n){
res.add(-1);
return res;
}
sum=sum+arr[j];
}else if(sum>s){
sum=sum-arr[i];
i=i+1;
if(sum==s){
res.add(i+1);
res.add(j+1);
return res;
}
}else{
res.add(i+1);
res.add(j+1);
return res;
}
if(j>=n || i>=n){
res.add(-1);
return res;
}
}
}
}
Passing all 165 test cases from geeksforgeeks
I also faced this problem in couple of interviews and came up with following best approach:
class MazSubArraySum {
public static void main(String[] args) {
int[] a = { -2, -3, 4, -1, -2, 1, 5, -3 };
System.out.println("Maximum contiguous sum is " + maxSubArraySum(a));
}
static int maxSubArraySum(int a[]) {
int size = a.length;
int currentindex = 0, end = 0, begin = 0;
int max_so_far = Integer.MIN_VALUE, max_ending_here = 0;
for (int i = 0; i < size; i++) {
max_ending_here = max_ending_here + a[i];
if (max_so_far < max_ending_here) {
max_so_far = max_ending_here;
begin = currentindex;
end = i;
}
if (max_ending_here < 0) {
max_ending_here = 0;
currentindex++;
}
}
System.out.println("begin and end: " + begin + "&" + end);
return max_so_far;
}
}
Below is the output:
begin and end: 2&6
Maximum contiguous sum is 7
Above solution is the best solution in terms of time and space complexity that is O(n).

Resources