Related
My solution scored only 40% correctness on Codility.
What am I doing wrong?
Here is the test result (https://codility.com/demo/results/trainingU7KSSG-YNX/)
Problem:
A zero-indexed array A consisting of N different integers is given. The array contains integers in the range [1..(N + 1)], which means that exactly one element is missing.
Your goal is to find that missing element.
Solution:
function solution(A) {
var output = 1;
var arrayLength = A.length;
if(!arrayLength){
return output;
}
if(arrayLength == 1) {
return A[0] + 1;
}
var sorted = A.sort(sortingFn);
for(var i = 0; i < A.length - 1; i++) {
if(A[i+1] - A[i] > 1) {
output = A[i] + 1;
break;
}
}
return output;
}
function sortingFn(a, b) {
return a - b;
}
Result
Your algorithm find the missing element by comparing neighboring elements in the array. This means it is incapable of handling cases where the first or last element is missing, as these only have a single neighbor.
Consider as an example [1, 2, 3]. The missing element would be 4. But since 4 has precisely one neighbor (3), it can't be found by the algorithm, and 1 will be returned.
In addition your algorithm is rather inefficient, as sorting takes O(n lg n), while the problem is solveable in O(n):
find_missing(arr):
s = sum(arr)
s' = (len(arr) + 1) * (len(arr) + 2) / 2
return s' - s
This code works by summing up all elements in the array and comparing it to expected sum, if all elements were present. The advantage of this approach is that it only requires linear operations and will find the missing element with relative simplicity.
Try this in c#:
using System;
using System.Linq;
private static int PermMissingElem(int[] A)
{
if (!A.Any() || !A.Any(x => x == 1)) { return 1; }
var size = A.Length;
var numberTwoList = Enumerable.Range(1, size);
var failNumber = numberTwoList.Except(A);
if (!failNumber.Any()) { return A.Max() + 1; }
return failNumber.FirstOrDefault();
}
Well, when the last element is missing, you obviously return 1, since your if statement's condition is always false. Same for first element.
Take as example this input:
1 2 3 4 5
the difference will be always 1, but element 6 is missing.
The reason for this incapability of your algorithm to catch these cases, is that it examines neighboring elements (A[i + 1] and A[i]).
JS solution #1
function solution(A) {
if (A.length === 1) {
return A[0] > 1 ? 1 : 2;
}
const map = {};
let max = 0;
for (let i = 0, len = A.length; i < len; i++) {
map[A[i]] = A[i];
if (A[i] > max) {
max = A[i]
}
}
for (let i = 0, len = A.length; i < len; i++) {
if (!map[i + 1]) {
return i + 1;
}
}
return max + 1
}
JS solution #2
function solution(A) {
const s = A.reduce((a, b) => {return a + b}, 0);
const s2 = (A.length + 1) * (A.length + 2) / 2
return s2 - s;
}
try this arrays (like the end test):
[1,2,3] -> must return 4;
[1] -> must return 2;
[2] -> must return 1;
[2,3] -> must return 1;
[1, 3] -> 2
But for #2 solution [4] returns -1 and for [123] returns -120. The test will show 100 points. But actually, it doesn't work as expected on my opinion.
Both solutions work with the same performance.
Try this javascript function:
function solution(A) {
let givenSum = 0;
let expectedSum = 0;
let size = A.length;
for(let i = 1; i <= size +1; i++){
expectedSum = expectedSum + i;
}
for(let i = 0; i < size; i++){
givenSum += A[i];
}
return expectedSum - givenSum;
}
here is my solution:
https://app.codility.com/demo/results/trainingMZWVVT-55Y/
function solution(A) {
A = A.sort((a,b)=>a-b)
if(A[0]!==1) return 1
for(let i = 0; i < A.length; i++)
{
if(A[i+1]-A[i]!==1) return A[i] + 1
}
return A[A.length] + 1
}
Tested on Codility with 100% score see here
The solution i implemented is using set difference. since the question guaranties exactly one element is missing.
def solution(A):
# write your code in Python 3.6
N = len(A)
difference = set(range(1, N+2)) - set(A)
return difference.pop()
So the problem is:
Write a program to find the nth super ugly number.
Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k. For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] is the sequence of the first 12 super ugly numbers given primes = [2, 7, 13, 19] of size 4.
So my algorithm basically finds all possible factors using the pattern they follow, pushes them to an array, sorts that array and then returns the nth value in the array. It accurately calculates all of them, however, is too slow with high nth values.
My question is what the proper way to do this is as I'm sure there has to be a more straightforward solution. I'm mostly curious about the theory behind finding it and if there's some kind of closed formula for this.
var nthSuperUglyNumber = function(n, primes) {
xprimes = primes;
var uglies = [1];
uglies = getUglyNumbers(n, primes, uglies);
// return uglies[n-1];
return uglies[n - 1];
};
// 3 4
//1, 2,3,5, || 4,6,10, 9,15, 25, || 8,12,20,18,30,50, 27,45,75, 125 ||
// 3,2,1 6,3,1, 10,4,1
// 1 1 1
//1, 2,3 || 4,6, 9, || 8,12,18, 27 || 16,24,36,54, 81
// 2,1 3,1 4,1 5,1
//
//1, 2,3,5,7 || 4,6,10,14 9,15,21 25,35, 49 ||
// 4,3,2,1 || 10,6,3,1
var getUglyNumbers = function(n, primes, uglies) {
if (n == 1) {
return uglies;
}
var incrFactor = [];
var j = 0;
// Initial factor and uglies setup
for (; j < primes.length; j += 1) {
incrFactor[j] = primes.length - j;
uglies.push(primes[j]);
}
//recrusive algo
uglies = calcUglies(n, uglies, incrFactor);
uglies.sort(function(a, b) {
return a - b;
});
return uglies;
};
var calcUglies = function(n, uglies, incrFactor) {
if (uglies.length >= 5 * n) return uglies;
var currlength = uglies.length;
var j = 0;
for (j = 0; j < xprimes.length; j += 1) {
var i = 0;
var start = currlength - incrFactor[j];
for (i = start; i < currlength; i += 1) {
uglies.push(xprimes[j] * uglies[i]);
}
}
// Upgrades the factors to level 2
for (j = 1; j < xprimes.length; j += 1) {
incrFactor[xprimes.length - 1 - j] = incrFactor[xprimes.length - j] + incrFactor[xprimes.length - 1 - j];
}
return calcUglies(n, uglies, incrFactor);
};
public static ArrayList<Integer> superUgly(int[] primes,int size)
{
Arrays.sort(primes);
int pLen = primes.length;
ArrayList<Integer> ans = new ArrayList<>();
ans.add(1);
PriorityQueue<pair> priorityQueue = new PriorityQueue<>(Comparator.comparingInt(p -> p.value));
HashSet<Integer> hashSet = new HashSet<>();
int next_ugly_number;
int[] indices = new int[pLen];
for(int i=0;i<pLen;i++) {
hashSet.add(primes[i]);
priorityQueue.add(new pair(i,primes[i]));
}
while(ans.size()!=size+1)
{
pair pair = priorityQueue.poll();
next_ugly_number = pair.value;
ans.add(next_ugly_number);
indices[pair.index]+=1;
int temp = ans.get(indices[pair.index])*primes[pair.index];
if (!hashSet.contains(temp))
{
priorityQueue.add(new pair(pair.index,temp));
hashSet.add(temp);
}
else {
while(hashSet.contains(temp))
{
indices[pair.index]+=1;
temp = ans.get(indices[pair.index])*primes[pair.index];
}
priorityQueue.add(new pair(pair.index,temp));
hashSet.add(temp);
}
}
ans.remove(0);
return ans;
}
Pair class is
class pair
{
int index,value;
public pair(int i,int v)
{
index = i;
value = v;
}
}
It returns a list of ugly numbers of size 'size'.
I am using priority queue to find minimum for every loop and also a hashset to avoid duplicate entries in priorityQueue.
So its time complexity is O(n log(k)) where n is size and k is primes array size.
This is the most optimal solution I could write using Dynamic Programming in Python.
Time complexity: O(n * k)
Space Complexity: O(n)
from typing import List
def super_ugly_numbers(n: int, primes: List[int]) -> int:
# get nth super ugly number
ugly_nums = [0] * n
ugly_nums[0] = 1
length = len(primes)
mul_indices = [0] * length
multipliers = primes[:]
for index in range(1, n):
ugly_nums[index] = min(multipliers)
for in_index in range(length):
if ugly_nums[index] == multipliers[in_index]:
mul_indices[in_index] += 1
multipliers[in_index] = ugly_nums[mul_indices[in_index]] * primes[in_index]
return ugly_nums[n-1]
This algorithm performs better for large n.
primes := {2, 7, 13, 19}
set list := {1}
for i in 1..n-1:
set k = list[0]
for p in primes:
insert p*k into list unless p*k is in list
remove list[0] from list
return list[0]
If inserting in order is hard, you can just insert the elements into the list at the end and sort the list just after removing list[0].
import java.util.*;
import java.lang.*;
import java.io.*;
public class Solution{
public static void main(String[] args) {
Scanner fi = new Scanner(System.in);
int n=fi.nextInt();
int i;
int primes[] ={2,3,5};
HashSet<Integer> hm=new HashSet<>();
PriorityQueue<Integer> pq=new PriorityQueue<>();
TreeSet<Integer> tr=new TreeSet<>();
tr.add(1);
pq.add(1);
hm.add(1);
for (i=0;i<primes.length;i++){
tr.add(primes[i]);
pq.add(primes[i]);
hm.add(primes[i]);
}
int size=tr.size();
while (size < n){
int curr=pq.poll();
for (i=0;i<primes.length;i++){
if (!hm.contains(curr*primes[i])) {
tr.add(curr * primes[i]);
hm.add(curr*primes[i]);
pq.add(curr*primes[i]);
size++;
}
}
}
System.out.println(tr);
}
}
This might as Help as TreeSet maintains element in sorted order so need to worry about index.
Given a sorted list of numbers, I would like to find the longest subsequence where the differences between successive elements are geometrically increasing. So if the list is
1, 2, 3, 4, 7, 15, 27, 30, 31, 81
then the subsequence is 1, 3, 7, 15, 31. Alternatively consider 1, 2, 5, 6, 11, 15, 23, 41, 47 which has subsequence 5, 11, 23, 47 with a = 3 and k = 2.
Can this be solved in O(n2) time? Where n is the length of the list.
I am interested both in the general case where the progression of differences is ak, ak2, ak3, etc., where both a and k are integers, and in the special case where a = 1, so the progression of difference is k, k2, k3, etc.
Update
I have made an improvement of the algorithm that it takes an average of O(M + N^2) and memory needs of O(M+N). Mainly is the same that the protocol described below, but to calculate the possible factors A,K for ech diference D, I preload a table. This table takes less than a second to be constructed for M=10^7.
I have made a C implementation that takes less than 10minutes to solve N=10^5 diferent random integer elements.
Here is the source code in C: To execute just do: gcc -O3 -o findgeo findgeo.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include <time.h>
struct Factor {
int a;
int k;
struct Factor *next;
};
struct Factor *factors = 0;
int factorsL=0;
void ConstructFactors(int R) {
int a,k,C;
int R2;
struct Factor *f;
float seconds;
clock_t end;
clock_t start = clock();
if (factors) free(factors);
factors = malloc (sizeof(struct Factor) *((R>>1) + 1));
R2 = R>>1 ;
for (a=0;a<=R2;a++) {
factors[a].a= a;
factors[a].k=1;
factors[a].next=NULL;
}
factorsL=R2+1;
R2 = floor(sqrt(R));
for (k=2; k<=R2; k++) {
a=1;
C=a*k*(k+1);
while (C<R) {
C >>= 1;
f=malloc(sizeof(struct Factor));
*f=factors[C];
factors[C].a=a;
factors[C].k=k;
factors[C].next=f;
a++;
C=a*k*(k+1);
}
}
end = clock();
seconds = (float)(end - start) / CLOCKS_PER_SEC;
printf("Construct Table: %f\n",seconds);
}
void DestructFactors() {
int i;
struct Factor *f;
for (i=0;i<factorsL;i++) {
while (factors[i].next) {
f=factors[i].next->next;
free(factors[i].next);
factors[i].next=f;
}
}
free(factors);
factors=NULL;
factorsL=0;
}
int ipow(int base, int exp)
{
int result = 1;
while (exp)
{
if (exp & 1)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
void findGeo(int **bestSolution, int *bestSolutionL,int *Arr, int L) {
int i,j,D;
int mustExistToBeBetter;
int R=Arr[L-1]-Arr[0];
int *possibleSolution;
int possibleSolutionL=0;
int exp;
int NextVal;
int idx;
int kMax,aMax;
float seconds;
clock_t end;
clock_t start = clock();
kMax = floor(sqrt(R));
aMax = floor(R/2);
ConstructFactors(R);
*bestSolutionL=2;
*bestSolution=malloc(0);
possibleSolution = malloc(sizeof(int)*(R+1));
struct Factor *f;
int *H=malloc(sizeof(int)*(R+1));
memset(H,0, sizeof(int)*(R+1));
for (i=0;i<L;i++) {
H[ Arr[i]-Arr[0] ]=1;
}
for (i=0; i<L-2;i++) {
for (j=i+2; j<L; j++) {
D=Arr[j]-Arr[i];
if (D & 1) continue;
f = factors + (D >>1);
while (f) {
idx=Arr[i] + f->a * f->k - Arr[0];
if ((f->k <= kMax)&& (f->a<aMax)&&(idx<=R)&&H[idx]) {
if (f->k ==1) {
mustExistToBeBetter = Arr[i] + f->a * (*bestSolutionL);
} else {
mustExistToBeBetter = Arr[i] + f->a * f->k * (ipow(f->k,*bestSolutionL) - 1)/(f->k-1);
}
if (mustExistToBeBetter< Arr[L-1]+1) {
idx= floor(mustExistToBeBetter - Arr[0]);
} else {
idx = R+1;
}
if ((idx<=R)&&H[idx]) {
possibleSolution[0]=Arr[i];
possibleSolution[1]=Arr[i] + f->a*f->k;
possibleSolution[2]=Arr[j];
possibleSolutionL=3;
exp = f->k * f->k * f->k;
NextVal = Arr[j] + f->a * exp;
idx=NextVal - Arr[0];
while ( (idx<=R) && H[idx]) {
possibleSolution[possibleSolutionL]=NextVal;
possibleSolutionL++;
exp = exp * f->k;
NextVal = NextVal + f->a * exp;
idx=NextVal - Arr[0];
}
if (possibleSolutionL > *bestSolutionL) {
free(*bestSolution);
*bestSolution = possibleSolution;
possibleSolution = malloc(sizeof(int)*(R+1));
*bestSolutionL=possibleSolutionL;
kMax= floor( pow (R, 1/ (*bestSolutionL) ));
aMax= floor(R / (*bestSolutionL));
}
}
}
f=f->next;
}
}
}
if (*bestSolutionL == 2) {
free(*bestSolution);
possibleSolutionL=0;
for (i=0; (i<2)&&(i<L); i++ ) {
possibleSolution[possibleSolutionL]=Arr[i];
possibleSolutionL++;
}
*bestSolution = possibleSolution;
*bestSolutionL=possibleSolutionL;
} else {
free(possibleSolution);
}
DestructFactors();
free(H);
end = clock();
seconds = (float)(end - start) / CLOCKS_PER_SEC;
printf("findGeo: %f\n",seconds);
}
int compareInt (const void * a, const void * b)
{
return *(int *)a - *(int *)b;
}
int main(void) {
int N=100000;
int R=10000000;
int *A = malloc(sizeof(int)*N);
int *Sol;
int SolL;
int i;
int *S=malloc(sizeof(int)*R);
for (i=0;i<R;i++) S[i]=i+1;
for (i=0;i<N;i++) {
int r = rand() % (R-i);
A[i]=S[r];
S[r]=S[R-i-1];
}
free(S);
qsort(A,N,sizeof(int),compareInt);
/*
int step = floor(R/N);
A[0]=1;
for (i=1;i<N;i++) {
A[i]=A[i-1]+step;
}
*/
findGeo(&Sol,&SolL,A,N);
printf("[");
for (i=0;i<SolL;i++) {
if (i>0) printf(",");
printf("%d",Sol[i]);
}
printf("]\n");
printf("Size: %d\n",SolL);
free(Sol);
free(A);
return EXIT_SUCCESS;
}
Demostration
I will try to demonstrate that the algorithm that I proposed is in average for an equally distributed random sequence. I’m not a mathematician and I am not used to do this kind of demonstrations, so please fill free to correct me any error that you can see.
There are 4 indented loops, the two firsts are the N^2 factor. The M is for the calculation of the possible factors table).
The third loop is executed only once in average for each pair. You can see this checking the size of the pre-calculated factors table. It’s size is M when N->inf. So the average steps for each pair is M/M=1.
So the proof happens to check that the forth loop. (The one that traverses the good made sequences is executed less that or equal O(N^2) for all the pairs.
To demonstrate that, I will consider two cases: one where M>>N and other where M ~= N. Where M is the maximum difference of the initial array: M= S(n)-S(1).
For the first case, (M>>N) the probability to find a coincidence is p=N/M. To start a sequence, it must coincide the second and the b+1 element where b is the length of the best sequence until now. So the loop will enter times. And the average length of this series (supposing an infinite series) is . So the total number of times that the loop will be executed is . And this is close to 0 when M>>N. The problem here is when M~=N.
Now lets consider this case where M~=N. Lets consider that b is the best sequence length until now. For the case A=k=1, then the sequence must start before N-b, so the number of sequences will be N-b, and the times that will go for the loop will be a maximum of (N-b)*b.
For A>1 and k=1 we can extrapolate to where d is M/N (the average distance between numbers). If we add for all A’s from 1 to dN/b then we see a top limit of:
For the cases where k>=2, we see that the sequence must start before , So the loop will enter an average of and adding for all As from 1 to dN/k^b, it gives a limit of
Here, the worst case is when b is minimum. Because we are considering minimum series, lets consider a very worst case of b= 2 so the number of passes for the 4th loop for a given k will be less than
.
And if we add all k’s from 2 to infinite will be:
So adding all the passes for k=1 and k>=2, we have a maximum of:
Note that d=M/N=1/p.
So we have two limits, One that goes to infinite when d=1/p=M/N goes to 1 and other that goes to infinite when d goes to infinite. So our limit is the minimum of both, and the worst case is when both equetions cross. So if we solve the equation:
we see that the maximum is when d=1.353
So it is demonstrated that the forth loops will be processed less than 1.55N^2 times in total.
Of course, this is for the average case. For the worst case I am not able to find a way to generate series whose forth loop are higher than O(N^2), and I strongly believe that they does not exist, but I am not a mathematician to prove it.
Old Answer
Here is a solution in average of O((n^2)*cube_root(M)) where M is the difference between the first and last element of the array. And memory requirements of O(M+N).
1.- Construct an array H of length M so that M[i - S[0]]=true if i exists in the initial array and false if it does not exist.
2.- For each pair in the array S[j], S[i] do:
2.1 Check if it can be the first and third elements of a possible solution. To do so, calculate all possible A,K pairs that meet the equation S(i) = S(j) + AK + AK^2. Check this SO question to see how to solve this problem. And check that exist the second element: S[i]+ A*K
2.2 Check also that exist the element one position further that the best solution that we have. For example, if the best solution that we have until now is 4 elements long then check that exist the element A[j] + AK + AK^2 + AK^3 + AK^4
2.3 If 2.1 and 2.2 are true, then iterate how long is this series and set as the bestSolution until now is is longer that the last.
Here is the code in javascript:
function getAKs(A) {
if (A / 2 != Math.floor(A / 2)) return [];
var solution = [];
var i;
var SR3 = Math.pow(A, 1 / 3);
for (i = 1; i <= SR3; i++) {
var B, C;
C = i;
B = A / (C * (C + 1));
if (B == Math.floor(B)) {
solution.push([B, C]);
}
B = i;
C = (-1 + Math.sqrt(1 + 4 * A / B)) / 2;
if (C == Math.floor(C)) {
solution.push([B, C]);
}
}
return solution;
}
function getBestGeometricSequence(S) {
var i, j, k;
var bestSolution = [];
var H = Array(S[S.length-1]-S[0]);
for (i = 0; i < S.length; i++) H[S[i] - S[0]] = true;
for (i = 0; i < S.length; i++) {
for (j = 0; j < i; j++) {
var PossibleAKs = getAKs(S[i] - S[j]);
for (k = 0; k < PossibleAKs.length; k++) {
var A = PossibleAKs[k][0];
var K = PossibleAKs[k][17];
var mustExistToBeBetter;
if (K==1) {
mustExistToBeBetter = S[j] + A * bestSolution.length;
} else {
mustExistToBeBetter = S[j] + A * K * (Math.pow(K,bestSolution.length) - 1)/(K-1);
}
if ((H[S[j] + A * K - S[0]]) && (H[mustExistToBeBetter - S[0]])) {
var possibleSolution=[S[j],S[j] + A * K,S[i]];
exp = K * K * K;
var NextVal = S[i] + A * exp;
while (H[NextVal - S[0]] === true) {
possibleSolution.push(NextVal);
exp = exp * K;
NextVal = NextVal + A * exp;
}
if (possibleSolution.length > bestSolution.length) {
bestSolution = possibleSolution;
}
}
}
}
}
return bestSolution;
}
//var A= [ 1, 2, 3,5,7, 15, 27, 30,31, 81];
var A=[];
for (i=1;i<=3000;i++) {
A.push(i);
}
var sol=getBestGeometricSequence(A);
$("#result").html(JSON.stringify(sol));
You can check the code here: http://jsfiddle.net/6yHyR/1/
I maintain the other solution because I believe that it is still better when M is very big compared to N.
Just to start with something, here is a simple solution in JavaScript:
var input = [0.7, 1, 2, 3, 4, 7, 15, 27, 30, 31, 81],
output = [], indexes, values, i, index, value, i_max_length,
i1, i2, i3, j1, j2, j3, difference12a, difference23a, difference12b, difference23b,
scale_factor, common_ratio_a, common_ratio_b, common_ratio_c,
error, EPSILON = 1e-9, common_ratio_is_integer,
resultDiv = $("#result");
for (i1 = 0; i1 < input.length - 2; ++i1) {
for (i2 = i1 + 1; i2 < input.length - 1; ++i2) {
scale_factor = difference12a = input[i2] - input[i1];
for (i3 = i2 + 1; i3 < input.length; ++i3) {
difference23a = input[i3] - input[i2];
common_ratio_1a = difference23a / difference12a;
common_ratio_2a = Math.round(common_ratio_1a);
error = Math.abs((common_ratio_2a - common_ratio_1a) / common_ratio_1a);
common_ratio_is_integer = error < EPSILON;
if (common_ratio_2a > 1 && common_ratio_is_integer) {
indexes = [i1, i2, i3];
j1 = i2;
j2 = i3
difference12b = difference23a;
for (j3 = j2 + 1; j3 < input.length; ++j3) {
difference23b = input[j3] - input[j2];
common_ratio_1b = difference23b / difference12b;
common_ratio_2b = Math.round(common_ratio_1b);
error = Math.abs((common_ratio_2b - common_ratio_1b) / common_ratio_1b);
common_ratio_is_integer = error < EPSILON;
if (common_ratio_is_integer && common_ratio_2a === common_ratio_2b) {
indexes.push(j3);
j1 = j2;
j2 = j3
difference12b = difference23b;
}
}
values = [];
for (i = 0; i < indexes.length; ++i) {
index = indexes[i];
value = input[index];
values.push(value);
}
output.push(values);
}
}
}
}
if (output !== []) {
i_max_length = 0;
for (i = 1; i < output.length; ++i) {
if (output[i_max_length].length < output[i].length)
i_max_length = i;
}
for (i = 0; i < output.length; ++i) {
if (output[i_max_length].length == output[i].length)
resultDiv.append("<p>[" + output[i] + "]</p>");
}
}
Output:
[1, 3, 7, 15, 31]
I find the first three items of every subsequence candidate, calculate the scale factor and the common ratio from them, and if the common ratio is integer, then I iterate over the remaining elements after the third one, and add those to the subsequence, which fit into the geometric progression defined by the first three items. As a last step, I select the sebsequence/s which has/have the largest length.
In fact it is exactly the same question as Longest equally-spaced subsequence, you just have to consider the logarithm of your data. If the sequence is a, ak, ak^2, ak^3, the logarithmique value is ln(a), ln(a) + ln(k), ln(a)+2ln(k), ln(a)+3ln(k), so it is equally spaced. The opposite is of course true. There is a lot of different code in the question above.
I don't think the special case a=1 can be resolved more efficiently than an adaptation from an algorithm above.
Here is my solution in Javascript. It should be close to O(n^2) except may be in some pathological cases.
function bsearch(Arr,Val, left,right) {
if (left == right) return left;
var m=Math.floor((left + right) /2);
if (Val <= Arr[m]) {
return bsearch(Arr,Val,left,m);
} else {
return bsearch(Arr,Val,m+1,right);
}
}
function findLongestGeometricSequence(S) {
var bestSolution=[];
var i,j,k;
var H={};
for (i=0;i<S.length;i++) H[S[i]]=true;
for (i=0;i<S.length;i++) {
for (j=0;j<i;j++) {
for (k=j+1;k<i;) {
var possibleSolution=[S[j],S[k],S[i]];
var K = (S[i] - S[k]) / (S[k] - S[j]);
var A = (S[k] - S[j]) * (S[k] - S[j]) / (S[i] - S[k]);
if ((Math.floor(K) == K) && (Math.floor(A)==A)) {
exp= K*K*K;
var NextVal= S[i] + A * exp;
while (H[NextVal] === true) {
possibleSolution.push(NextVal);
exp = exp * K;
NextVal= NextVal + A * exp;
}
if (possibleSolution.length > bestSolution.length)
bestSolution=possibleSolution;
K--;
} else {
K=Math.floor(K);
}
if (K>0) {
var NextPossibleMidValue= (S[i] + K*S[j]) / (K +1);
k++;
if (S[k]<NextPossibleMidValue) {
k=bsearch(S,NextPossibleMidValue, k+1, i);
}
} else {
k=i;
}
}
}
}
return bestSolution;
}
function Run() {
var MyS= [0.7, 1, 2, 3, 4, 5,6,7, 15, 27, 30,31, 81];
var sol = findLongestGeometricSequence(MyS);
alert(JSON.stringify(sol));
}
Small Explanation
If we take 3 numbers of the array S(j) < S(k) < S(i) then you can calculate a and k so that: S(k) = S(j) + a*k and S(i) = S(k) + a*k^2 (2 equations and 2 incognits). With that in mind, you can check if exist a number in the array that is S(next) = S(i) + a*k^3. If that is the case, then continue checknng for S(next2) = S(next) + a*k^4 and so on.
This would be a O(n^3) solution, but you can hava advantage that k must be integer in order to limit the S(k) points selected.
In case that a is known, then you can calculate a(k) and you need to check only one number in the third loop, so this case will be clearly a O(n^2).
I think this task is related with not so long ago posted Longest equally-spaced subsequence. I've just modified my algorithm in Python a little bit:
from math import sqrt
def add_precalc(precalc, end, (a, k), count, res, N):
if end + a * k ** res[1]["count"] > N: return
x = end + a * k ** count
if x > N or x < 0: return
if precalc[x] is None: return
if (a, k) not in precalc[x]:
precalc[x][(a, k)] = count
return
def factors(n):
res = []
for x in range(1, int(sqrt(n)) + 1):
if n % x == 0:
y = n / x
res.append((x, y))
res.append((y, x))
return res
def work(input):
precalc = [None] * (max(input) + 1)
for x in input: precalc[x] = {}
N = max(input)
res = ((0, 0), {"end":0, "count":0})
for i, x in enumerate(input):
for y in input[i::-1]:
for a, k in factors(x - y):
if (a, k) in precalc[x]: continue
add_precalc(precalc, x, (a, k), 2, res, N)
for step, count in precalc[x].iteritems():
count += 1
if count > res[1]["count"]: res = (step, {"end":x, "count":count})
add_precalc(precalc, x, step, count, res, N)
precalc[x] = None
d = [res[1]["end"]]
for x in range(res[1]["count"] - 1, 0, -1):
d.append(d[-1] - res[0][0] * res[0][1] ** x)
d.reverse()
return d
explanation
Traversing the array
For each previous element of the array calculate factors of the difference between current and taken previous element and then precalculate next possible element of the sequence and saving it to precalc array
So when arriving at element i there're already all possible sequences with element i in the precalc array, so we have to calculate next possible element and save it to precalc.
Currently there's one place in algorithm that could be slow - factorization of each previous number. I think it could be made faster with two optimizations:
more effective factorization algorithm
find a way not to see at each element of array, using the fact that array is sorted and there's already a precalculated sequences
Python:
def subseq(a):
seq = []
aset = set(a)
for i, x in enumerate(a):
# elements after x
for j, x2 in enumerate(a[i+1:]):
j += i + 1 # enumerate starts j at 0, we want a[j] = x2
bk = x2 - x # b*k (assuming k and k's exponent start at 1)
# given b*k, bruteforce values of k
for k in range(1, bk + 1):
items = [x, x2] # our subsequence so far
nextdist = bk * k # what x3 - x2 should look like
while items[-1] + nextdist in aset:
items.append(items[-1] + nextdist)
nextdist *= k
if len(items) > len(seq):
seq = items
return seq
Running time is O(dn^3), where d is the (average?) distance between two elements,
and n is of course len(a).
I was asked this question in a job interview, and I'd like to know how others would solve it. I'm most comfortable with Java, but solutions in other languages are welcome.
Given an array of numbers, nums, return an array of numbers products, where products[i] is the product of all nums[j], j != i.
Input : [1, 2, 3, 4, 5]
Output: [(2*3*4*5), (1*3*4*5), (1*2*4*5), (1*2*3*5), (1*2*3*4)]
= [120, 60, 40, 30, 24]
You must do this in O(N) without using division.
An explanation of polygenelubricants method is:
The trick is to construct the arrays (in the case for 4 elements):
{ 1, a[0], a[0]*a[1], a[0]*a[1]*a[2], }
{ a[1]*a[2]*a[3], a[2]*a[3], a[3], 1, }
Both of which can be done in O(n) by starting at the left and right edges respectively.
Then, multiplying the two arrays element-by-element gives the required result.
My code would look something like this:
int a[N] // This is the input
int products_below[N];
int p = 1;
for (int i = 0; i < N; ++i) {
products_below[i] = p;
p *= a[i];
}
int products_above[N];
p = 1;
for (int i = N - 1; i >= 0; --i) {
products_above[i] = p;
p *= a[i];
}
int products[N]; // This is the result
for (int i = 0; i < N; ++i) {
products[i] = products_below[i] * products_above[i];
}
If you need the solution be O(1) in space as well, you can do this (which is less clear in my opinion):
int a[N] // This is the input
int products[N];
// Get the products below the current index
int p = 1;
for (int i = 0; i < N; ++i) {
products[i] = p;
p *= a[i];
}
// Get the products above the current index
p = 1;
for (int i = N - 1; i >= 0; --i) {
products[i] *= p;
p *= a[i];
}
Here is a small recursive function (in C++) to do the modification in-place. It requires O(n) extra space (on stack) though. Assuming the array is in a and N holds the array length, we have:
int multiply(int *a, int fwdProduct, int indx) {
int revProduct = 1;
if (indx < N) {
revProduct = multiply(a, fwdProduct*a[indx], indx+1);
int cur = a[indx];
a[indx] = fwdProduct * revProduct;
revProduct *= cur;
}
return revProduct;
}
Here's my attempt to solve it in Java. Apologies for the non-standard formatting, but the code has a lot of duplication, and this is the best I can do to make it readable.
import java.util.Arrays;
public class Products {
static int[] products(int... nums) {
final int N = nums.length;
int[] prods = new int[N];
Arrays.fill(prods, 1);
for (int
i = 0, pi = 1 , j = N-1, pj = 1 ;
(i < N) && (j >= 0) ;
pi *= nums[i++] , pj *= nums[j--] )
{
prods[i] *= pi ; prods[j] *= pj ;
}
return prods;
}
public static void main(String[] args) {
System.out.println(
Arrays.toString(products(1, 2, 3, 4, 5))
); // prints "[120, 60, 40, 30, 24]"
}
}
The loop invariants are pi = nums[0] * nums[1] *.. nums[i-1] and pj = nums[N-1] * nums[N-2] *.. nums[j+1]. The i part on the left is the "prefix" logic, and the j part on the right is the "suffix" logic.
Recursive one-liner
Jasmeet gave a (beautiful!) recursive solution; I've turned it into this (hideous!) Java one-liner. It does in-place modification, with O(N) temporary space in the stack.
static int multiply(int[] nums, int p, int n) {
return (n == nums.length) ? 1
: nums[n] * (p = multiply(nums, nums[n] * (nums[n] = p), n + 1))
+ 0*(nums[n] *= p);
}
int[] arr = {1,2,3,4,5};
multiply(arr, 1, 0);
System.out.println(Arrays.toString(arr));
// prints "[120, 60, 40, 30, 24]"
Translating Michael Anderson's solution into Haskell:
otherProducts xs = zipWith (*) below above
where below = scanl (*) 1 $ init xs
above = tail $ scanr (*) 1 xs
Sneakily circumventing the "no divisions" rule:
sum = 0.0
for i in range(a):
sum += log(a[i])
for i in range(a):
output[i] = exp(sum - log(a[i]))
Here you go, simple and clean solution with O(N) complexity:
int[] a = {1,2,3,4,5};
int[] r = new int[a.length];
int x = 1;
r[0] = 1;
for (int i=1;i<a.length;i++){
r[i]=r[i-1]*a[i-1];
}
for (int i=a.length-1;i>0;i--){
x=x*a[i];
r[i-1]=x*r[i-1];
}
for (int i=0;i<r.length;i++){
System.out.println(r[i]);
}
Travel Left->Right and keep saving product. Call it Past. -> O(n)
Travel Right -> left keep the product. Call it Future. -> O(n)
Result[i] = Past[i-1] * future[i+1] -> O(n)
Past[-1] = 1; and Future[n+1]=1;
O(n)
C++, O(n):
long long prod = accumulate(in.begin(), in.end(), 1LL, multiplies<int>());
transform(in.begin(), in.end(), back_inserter(res),
bind1st(divides<long long>(), prod));
Here is my solution in modern C++. It makes use of std::transform and is pretty easy to remember.
Online code (wandbox).
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
vector<int>& multiply_up(vector<int>& v){
v.insert(v.begin(),1);
transform(v.begin()+1, v.end()
,v.begin()
,v.begin()+1
,[](auto const& a, auto const& b) { return b*a; }
);
v.pop_back();
return v;
}
int main() {
vector<int> v = {1,2,3,4,5};
auto vr = v;
reverse(vr.begin(),vr.end());
multiply_up(v);
multiply_up(vr);
reverse(vr.begin(),vr.end());
transform(v.begin(),v.end()
,vr.begin()
,v.begin()
,[](auto const& a, auto const& b) { return b*a; }
);
for(auto& i: v) cout << i << " ";
}
Precalculate the product of the numbers to the left and to the right of each element.
For every element the desired value is the product of it's neigbors's products.
#include <stdio.h>
unsigned array[5] = { 1,2,3,4,5};
int main(void)
{
unsigned idx;
unsigned left[5]
, right[5];
left[0] = 1;
right[4] = 1;
/* calculate products of numbers to the left of [idx] */
for (idx=1; idx < 5; idx++) {
left[idx] = left[idx-1] * array[idx-1];
}
/* calculate products of numbers to the right of [idx] */
for (idx=4; idx-- > 0; ) {
right[idx] = right[idx+1] * array[idx+1];
}
for (idx=0; idx <5 ; idx++) {
printf("[%u] Product(%u*%u) = %u\n"
, idx, left[idx] , right[idx] , left[idx] * right[idx] );
}
return 0;
}
Result:
$ ./a.out
[0] Product(1*120) = 120
[1] Product(1*60) = 60
[2] Product(2*20) = 40
[3] Product(6*5) = 30
[4] Product(24*1) = 24
(UPDATE: now I look closer, this uses the same method as Michael Anderson, Daniel Migowski and polygenelubricants above)
Tricky:
Use the following:
public int[] calc(int[] params) {
int[] left = new int[n-1]
in[] right = new int[n-1]
int fac1 = 1;
int fac2 = 1;
for( int i=0; i<n; i++ ) {
fac1 = fac1 * params[i];
fac2 = fac2 * params[n-i];
left[i] = fac1;
right[i] = fac2;
}
fac = 1;
int[] results = new int[n];
for( int i=0; i<n; i++ ) {
results[i] = left[i] * right[i];
}
Yes, I am sure i missed some i-1 instead of i, but thats the way to solve it.
This is O(n^2) but f# is soooo beautiful:
List.fold (fun seed i -> List.mapi (fun j x -> if i=j+1 then x else x*i) seed)
[1;1;1;1;1]
[1..5]
There also is a O(N^(3/2)) non-optimal solution. It is quite interesting, though.
First preprocess each partial multiplications of size N^0.5(this is done in O(N) time complexity). Then, calculation for each number's other-values'-multiple can be done in 2*O(N^0.5) time(why? because you only need to multiple the last elements of other ((N^0.5) - 1) numbers, and multiply the result with ((N^0.5) - 1) numbers that belong to the group of the current number). Doing this for each number, one can get O(N^(3/2)) time.
Example:
4 6 7 2 3 1 9 5 8
partial results:
4*6*7 = 168
2*3*1 = 6
9*5*8 = 360
To calculate the value of 3, one needs to multiply the other groups' values 168*360, and then with 2*1.
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5 };
int[] result = { 1, 1, 1, 1, 1 };
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < i; j++) {
result[i] *= arr[j];
}
for (int k = arr.length - 1; k > i; k--) {
result[i] *= arr[k];
}
}
for (int i : result) {
System.out.println(i);
}
}
This solution i came up with and i found it so clear what do you think!?
Based on Billz answer--sorry I can't comment, but here is a scala version that correctly handles duplicate items in the list, and is probably O(n):
val list1 = List(1, 7, 3, 3, 4, 4)
val view = list1.view.zipWithIndex map { x => list1.view.patch(x._2, Nil, 1).reduceLeft(_*_)}
view.force
returns:
List(1008, 144, 336, 336, 252, 252)
Adding my javascript solution here as I didn't find anyone suggesting this.
What is to divide, except to count the number of times you can extract a number from another number? I went through calculating the product of the whole array, and then iterate over each element, and substracting the current element until zero:
//No division operation allowed
// keep substracting divisor from dividend, until dividend is zero or less than divisor
function calculateProducsExceptCurrent_NoDivision(input){
var res = [];
var totalProduct = 1;
//calculate the total product
for(var i = 0; i < input.length; i++){
totalProduct = totalProduct * input[i];
}
//populate the result array by "dividing" each value
for(var i = 0; i < input.length; i++){
var timesSubstracted = 0;
var divisor = input[i];
var dividend = totalProduct;
while(divisor <= dividend){
dividend = dividend - divisor;
timesSubstracted++;
}
res.push(timesSubstracted);
}
return res;
}
Just 2 passes up and down. Job done in O(N)
private static int[] multiply(int[] numbers) {
int[] multiplied = new int[numbers.length];
int total = 1;
multiplied[0] = 1;
for (int i = 1; i < numbers.length; i++) {
multiplied[i] = numbers[i - 1] * multiplied[i - 1];
}
for (int j = numbers.length - 2; j >= 0; j--) {
total *= numbers[j + 1];
multiplied[j] = total * multiplied[j];
}
return multiplied;
}
def productify(arr, prod, i):
if i < len(arr):
prod.append(arr[i - 1] * prod[i - 1]) if i > 0 else prod.append(1)
retval = productify(arr, prod, i + 1)
prod[i] *= retval
return retval * arr[i]
return 1
if __name__ == "__main__":
arr = [1, 2, 3, 4, 5]
prod = []
productify(arr, prod, 0)
print(prod)
Well,this solution can be considered that of C/C++.
Lets say we have an array "a" containing n elements
like a[n],then the pseudo code would be as below.
for(j=0;j<n;j++)
{
prod[j]=1;
for (i=0;i<n;i++)
{
if(i==j)
continue;
else
prod[j]=prod[j]*a[i];
}
One more solution, Using division. with twice traversal.
Multiply all the elements and then start dividing it by each element.
{-
Recursive solution using sqrt(n) subsets. Runs in O(n).
Recursively computes the solution on sqrt(n) subsets of size sqrt(n).
Then recurses on the product sum of each subset.
Then for each element in each subset, it computes the product with
the product sum of all other products.
Then flattens all subsets.
Recurrence on the run time is T(n) = sqrt(n)*T(sqrt(n)) + T(sqrt(n)) + n
Suppose that T(n) ≤ cn in O(n).
T(n) = sqrt(n)*T(sqrt(n)) + T(sqrt(n)) + n
≤ sqrt(n)*c*sqrt(n) + c*sqrt(n) + n
≤ c*n + c*sqrt(n) + n
≤ (2c+1)*n
∈ O(n)
Note that ceiling(sqrt(n)) can be computed using a binary search
and O(logn) iterations, if the sqrt instruction is not permitted.
-}
otherProducts [] = []
otherProducts [x] = [1]
otherProducts [x,y] = [y,x]
otherProducts a = foldl' (++) [] $ zipWith (\s p -> map (*p) s) solvedSubsets subsetOtherProducts
where
n = length a
-- Subset size. Require that 1 < s < n.
s = ceiling $ sqrt $ fromIntegral n
solvedSubsets = map otherProducts subsets
subsetOtherProducts = otherProducts $ map product subsets
subsets = reverse $ loop a []
where loop [] acc = acc
loop a acc = loop (drop s a) ((take s a):acc)
Here is my code:
int multiply(int a[],int n,int nextproduct,int i)
{
int prevproduct=1;
if(i>=n)
return prevproduct;
prevproduct=multiply(a,n,nextproduct*a[i],i+1);
printf(" i=%d > %d\n",i,prevproduct*nextproduct);
return prevproduct*a[i];
}
int main()
{
int a[]={2,4,1,3,5};
multiply(a,5,1,0);
return 0;
}
Here's a slightly functional example, using C#:
Func<long>[] backwards = new Func<long>[input.Length];
Func<long>[] forwards = new Func<long>[input.Length];
for (int i = 0; i < input.Length; ++i)
{
var localIndex = i;
backwards[i] = () => (localIndex > 0 ? backwards[localIndex - 1]() : 1) * input[localIndex];
forwards[i] = () => (localIndex < input.Length - 1 ? forwards[localIndex + 1]() : 1) * input[localIndex];
}
var output = new long[input.Length];
for (int i = 0; i < input.Length; ++i)
{
if (0 == i)
{
output[i] = forwards[i + 1]();
}
else if (input.Length - 1 == i)
{
output[i] = backwards[i - 1]();
}
else
{
output[i] = forwards[i + 1]() * backwards[i - 1]();
}
}
I'm not entirely certain that this is O(n), due to the semi-recursion of the created Funcs, but my tests seem to indicate that it's O(n) in time.
To be complete here is the code in Scala:
val list1 = List(1, 2, 3, 4, 5)
for (elem <- list1) println(list1.filter(_ != elem) reduceLeft(_*_))
This will print out the following:
120
60
40
30
24
The program will filter out the current elem (_ != elem); and multiply the new list with reduceLeft method. I think this will be O(n) if you use scala view or Iterator for lazy eval.
// This is the recursive solution in Java
// Called as following from main product(a,1,0);
public static double product(double[] a, double fwdprod, int index){
double revprod = 1;
if (index < a.length){
revprod = product2(a, fwdprod*a[index], index+1);
double cur = a[index];
a[index] = fwdprod * revprod;
revprod *= cur;
}
return revprod;
}
A neat solution with O(n) runtime:
For each element calculate the product of all the elements that occur before that and it store in an array "pre".
For each element calculate the product of all the elements that occur after that element and store it in an array "post"
Create a final array "result", for an element i,
result[i] = pre[i-1]*post[i+1];
Here is the ptyhon version
# This solution use O(n) time and O(n) space
def productExceptSelf(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
N = len(nums)
if N == 0: return
# Initialzie list of 1, size N
l_prods, r_prods = [1]*N, [1]*N
for i in range(1, N):
l_prods[i] = l_prods[i-1] * nums[i-1]
for i in reversed(range(N-1)):
r_prods[i] = r_prods[i+1] * nums[i+1]
result = [x*y for x,y in zip(l_prods,r_prods)]
return result
# This solution use O(n) time and O(1) space
def productExceptSelfSpaceOptimized(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
N = len(nums)
if N == 0: return
# Initialzie list of 1, size N
result = [1]*N
for i in range(1, N):
result[i] = result[i-1] * nums[i-1]
r_prod = 1
for i in reversed(range(N)):
result[i] *= r_prod
r_prod *= nums[i]
return result
I'm use to C#:
public int[] ProductExceptSelf(int[] nums)
{
int[] returnArray = new int[nums.Length];
List<int> auxList = new List<int>();
int multTotal = 0;
// If no zeros are contained in the array you only have to calculate it once
if(!nums.Contains(0))
{
multTotal = nums.ToList().Aggregate((a, b) => a * b);
for (int i = 0; i < nums.Length; i++)
{
returnArray[i] = multTotal / nums[i];
}
}
else
{
for (int i = 0; i < nums.Length; i++)
{
auxList = nums.ToList();
auxList.RemoveAt(i);
if (!auxList.Contains(0))
{
returnArray[i] = auxList.Aggregate((a, b) => a * b);
}
else
{
returnArray[i] = 0;
}
}
}
return returnArray;
}
Here is simple Scala version in Linear O(n) time:
def getProductEff(in:Seq[Int]):Seq[Int] = {
//create a list which has product of every element to the left of this element
val fromLeft = in.foldLeft((1, Seq.empty[Int]))((ac, i) => (i * ac._1, ac._2 :+ ac._1))._2
//create a list which has product of every element to the right of this element, which is the same as the previous step but in reverse
val fromRight = in.reverse.foldLeft((1,Seq.empty[Int]))((ac,i) => (i * ac._1,ac._2 :+ ac._1))._2.reverse
//merge the two list by product at index
in.indices.map(i => fromLeft(i) * fromRight(i))
}
This works because essentially the answer is an array which has product of all elements to the left and to the right.
import java.util.Arrays;
public class Pratik
{
public static void main(String[] args)
{
int[] array = {2, 3, 4, 5, 6}; // OUTPUT: 360 240 180 144 120
int[] products = new int[array.length];
arrayProduct(array, products);
System.out.println(Arrays.toString(products));
}
public static void arrayProduct(int array[], int products[])
{
double sum = 0, EPSILON = 1e-9;
for(int i = 0; i < array.length; i++)
sum += Math.log(array[i]);
for(int i = 0; i < array.length; i++)
products[i] = (int) (EPSILON + Math.exp(sum - Math.log(array[i])));
}
}
OUTPUT:
[360, 240, 180, 144, 120]
Time complexity : O(n)
Space complexity: O(1)
An array contains both positive and negative elements, find the maximum subarray whose sum equals 0.
The link in the current accepted answer requires to sign up for a membership and I do not its content.
This algorithm will find all subarrays with sum 0 and it can be easily modified to find the minimal one or to keep track of the start and end indexes. This algorithm is O(n).
Given an int[] input array, you can create an int[] tmp array where tmp[i] = tmp[i - 1] + input[i]; Each element of tmp will store the sum of the input up to that element(prefix sum of array).
Now if you check tmp, you'll notice that there might be values that are equal to each other. Let's say that this values are at indexes j an k with j < k, then the sum of the input till j is equal to the sum till k and this means that the sum of the portion of the array between j and k is 0! Specifically the 0 sum subarray will be from index j + 1 to k.
NOTE: if j + 1 == k, then k is 0 and that's it! ;)
NOTE: The algorithm should consider a virtual tmp[-1] = 0;
NOTE: An empty array has sum 0 and it's minimal and this special case should be brought up as well in an interview. Then the interviewer will say that doesn't count but that's another problem! ;)
The implementation can be done in different ways including using a HashMap with pairs but be careful with the special case in the NOTE section above.
Example:
int[] input = {4, 6, 3, -9, -5, 1, 3, 0, 2}
int[] tmp = {4, 10, 13, 4, -1, 0, 3, 3, 5}
Value 4 in tmp at index 0 and 3 ==> sum tmp 1 to 3 = 0, length (3 - 1) + 1 = 3
Value 0 in tmp at index 5 ==> sum tmp 0 to 5 = 0, length (5 - 0) + 1 = 6
Value 3 in tmp at index 6 and 7 ==> sum tmp 7 to 7 = 0, length (7 - 7) + 1 = 1
****UPDATE****
Assuming that in our tmp array we end up with multiple element with the same value then you have to consider every identical pair in it! Example (keep in mind the virtual '0' at index '-1'):
int[] array = {0, 1, -1, 0}
int[] tmp = {0, 1, 0, 0}
By applying the same algorithm described above the 0-sum subarrays are delimited by the following indexes (included):
[0] [0-2] [0-3] [1-2] [1-3] [3]
Although the presence of multiple entries with the same value might impact the complexity of the algorithm depending on the implementation, I believe that by using an inverted index on tmp (mapping a value to the indexes where it appears) we can keep the running time at O(n).
This is one the same lines as suggested by Gevorg but I have used a hash map for quick lookup. O(n) complexity used extra space though.
private static void subArraySumsZero()
{
int [] seed = new int[] {1,2,3,4,-9,6,7,-8,1,9};
int currSum = 0;
HashMap<Integer, Integer> sumMap = new HashMap<Integer, Integer>();
for(int i = 0 ; i < seed.length ; i ++)
{
currSum += seed[i];
if(currSum == 0)
{
System.out.println("subset : { 0 - " + i + " }");
}
else if(sumMap.get(currSum) != null)
{
System.out.println("subset : { "
+ (sumMap.get(currSum) + 1)
+ " - " + i + " }");
sumMap.put(currSum, i);
}
else
sumMap.put(currSum, i);
}
System.out.println("HASH MAP HAS: " + sumMap);
}
The output generated has index of elements (zero based):
subset : { 1 - 4 }
subset : { 3 - 7 }
subset : { 6 - 8 }
1. Given A[i]
A[i] | 2 | 1 | -1 | 0 | 2 | -1 | -1
-------+---|----|--------|---|----|---
sum[i] | 2 | 3 | 2 | 2 | 4 | 3 | 2
2. sum[i] = A[0] + A[1] + ...+ A[i]
3. build a map<Integer, Set>
4. loop through array sum, and lookup map to get the set and generate set, and push <sum[i], i> into map.
Complexity O(n)
Here's my implementation, it's the obvious approach so it's probably sub-optimized, but at least its clear. Please correct me if i'm wrong.
Starts from each index of the array and calculates and compares the individual sums (tempsum) with the desired sum (in this case, sum = 0). Since the integers are signed, we must calculate every possible combination.
If you don't need the full list of sub-arrays, you can always put conditions in the inner loop to break out of it. (Say you just want to know if such a sub-array exists, just return true when tempsum = sum).
public static string[] SubArraySumList(int[] array, int sum)
{
int tempsum;
List<string> list = new List<string>();
for (int i = 0; i < array.Length; i++)
{
tempsum = 0;
for (int j = i; j < array.Length; j++)
{
tempsum += array[j];
if (tempsum == sum)
{
list.Add(String.Format("[{0}-{1}]", i, j));
}
}
}
return list.ToArray();
}
Calling the function:
int[] array = SubArraySumList(new int { 0, -1, 1, 0 }, 0));
Printing the contents of the output array:
[0-0], [0-2], [0-3], [1-2], [1-3], [3-3]
Following solution finds max length subarray with a given sum k without using dynamic programming, but using simple rescursion. Here i_s is start index and i_e is end index for the current value of sum
##Input the array and sum to be found(0 in your case)
a = map(int,raw_input().split())
k = int(raw_input())
##initialize total sum=0
totalsum=0
##Recursive function to find max len 0
def findMaxLen(sumL,i_s,i_e):
if i_s<len(a)-1 and i_e>0:
if sumL==k:
print i_s, i_e
return (i_s,i_e)
else:
x = findMaxLen(sumL-a[i_s],i_s+1,i_e)
y = findMaxLen(sumL-a[i_e],i_s,i_e-1)
if x[1]-x[0]>y[1]-y[0]:
return x
else:
return y
else:
##Result not there
return (-1,-1)
## find total sum
for i in range(len(a)):
totalsum += a[i]
##if totalsum==0, max array is array itself
if totalsum == k:
print "seq found at",0,len(a)-1
##else use recursion
else:
print findMaxLen(totalsum,0,len(a)-1)
Time complexity is O(n) and space complexity is O(n) due to recursive memory stack
Here's an O(n) implementation in java
The idea is to iterate through the given array and for every element arr[i], calculate sum of elements form 0 to i, store each sum in HashMap.
If an element is 0, it's considerd as a a ZeroSum sub array.
if sum became 0, then there is a ZeroSum sub array, from 0 to i.
If the current sum has been seen before in HashMap, then there is a ZeroSum sub array, from that point to i.
Code:
import java.util.*;
import java.lang.*;
class Rextester
{
private static final int[] EMPTY = {};
// Returns int[] if arr[] has a subarray with sero sum
static int[] findZeroSumSubarray(int arr[])
{
if (arr.length == 0) return EMPTY;
// Creates an empty hashMap hM
HashMap<Integer, Integer> hM = new HashMap<Integer, Integer>();
// Initialize sum of elements
int sum = 0;
for (int i = 0; i < arr.length; i++)
{
sum += arr[i];
if (arr[i] == 0) //Current element is 0
{
return new int[]{0};
}
else if (sum == 0) // sum of elements from 0 to i is 0
{
return Arrays.copyOfRange(arr, 0, i+1);
}
else if (hM.get(sum) != null) // sum is already present in hash map
{
return Arrays.copyOfRange(arr, hM.get(sum)+1, i+1);
}
else
{
// Add sum to hash map
hM.put(sum, i);
}
}
// We reach here only when there is no subarray with 0 sum
return null;
}
public static void main(String arg[])
{
//int arr[] = {};
int arr[] = { 2, -3, 1, 4, 6}; //Case left
//int arr[] = { 0, 2, -3, 1, 4, 6}; //Case 0
//int arr[] = { 4, 2, -3, 1, 4}; // Case middle
int result[] = findZeroSumSubarray(arr);
if (result == EMPTY){
System.out.println("An empty array is ZeroSum, LOL");
}
else if ( result != null){
System.out.println("Found a subarray with 0 sum :" );
for (int i: result) System.out.println(i);
}
else
System.out.println("No Subarray with 0 sum");
}
}
Please see the experiment here: http://rextester.com/PAKT41271
An array contains positive and negative numbers. Find the sub-array that has the maximum sum
public static int findMaxSubArray(int[] array)
{
int max=0,cumulativeSum=0,i=0,start=0,end=0,savepoint=0;
while(i<array.length)
{
if(cumulativeSum+array[i]<0)
{
cumulativeSum=0;
savepoint=start;
start=i+1;
}
else
cumulativeSum=cumulativeSum+array[i];
if(cumulativeSum>max)
{
max=cumulativeSum;
savepoint=start;
end=i;
}
i++;
}
System.out.println("Max : "+max+" Start indices : "+savepoint+" end indices : "+end);
return max;
}
Below codes can find out every possible sub-array that has a sum being a given number, and (of course) it can find out the shortest and longest sub-array of that kind.
public static void findGivenSumSubarray(int arr[], int givenSum) {
int sum = 0;
int sStart = 0, sEnd = Integer.MAX_VALUE - 1; // Start & end position of the shortest sub-array
int lStart = Integer.MAX_VALUE - 1, lEnd = 0; // Start & end position of the longest sub-array
HashMap<Integer, ArrayList<Integer>> sums = new HashMap<>();
ArrayList<Integer> indices = new ArrayList<>();
indices.add(-1);
sums.put(0, indices);
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
indices = sums.get(sum - givenSum);
if(indices != null) {
for(int index : indices) {
System.out.println("From #" + (index + 1) + " to #" + i);
}
if(i - indices.get(indices.size() - 1) < (sEnd - sStart + 1)) {
sStart = indices.get(indices.size() - 1) + 1;
sEnd = i;
}
if(i - indices.get(0) > (lEnd - lStart + 1)) {
lStart = indices.get(0) + 1;
lEnd = i;
}
}
indices = sums.get(sum);
if(indices == null) {
indices = new ArrayList<>();
}
indices.add(i);
sums.put(sum, indices);
}
System.out.println("Shortest sub-arry: Length = " + (sEnd - sStart + 1) + ", [" + sStart + " - " + sEnd + "]");
System.out.println("Longest sub-arry: Length = " + (lEnd - lStart + 1) + ", [" + lStart + " - " + lEnd + "]");
}
Hope this help you.
private static void subArrayZeroSum(int array[] , int findSum){
Map<Integer,HashSet<Integer>> map = new HashMap<Integer,HashSet<Integer>>();
int sum = 0;
for(int index = 0 ; index < array.length ; index ++){
sum +=array[index];
if(array[index] == findSum){
System.out.println(" ["+index+"]");
}
if(sum == findSum && index > 0){
System.out.println(" [ 0 , "+index+" ]");
}
if(map.containsKey(sum)){
HashSet<Integer> set = map.get(sum);
if(set == null)
set = new HashSet<Integer>();
set.add(index);
map.put(sum, set);
for(int val : set){
if(val + 1 != index && (val + 1) < index){
System.out.println("["+(val + 1) +","+index+" ]");
}
}
}else{
HashSet<Integer> set = map.get(sum);
if(set == null)
set = new HashSet<Integer>();
set.add(index);
map.put(sum, set);
}
}
}
One of the solution:
Let's say we have an array of integer,
int[] arr = {2,1,-1,-2};
We will traverse using the for loop until we find the number < 0 OR <= 0
i = 2;
With the inner loop, we will traverse assign the value to j = i-1
So, We can able to find the positive value.
for(int i = 0; i<arr.length; i++){
int j = 0;
int sum = arr[i];
if(arr[i] < 0){
j = i - 1;
}
We will have one sum variable, which maintaining the sum of arr[i] and arr[j] and updating the result.
If the sum is < 0 then, we have to move left side of the array and so, we will decrement the j by one, j--
for(j = i-1; j>=0; j--) {
sum = sum + arr[j];
if(sum == 0){
System.out.println("Index from j=" + j+ " to i=" + i);
return true;
}
}
If the sum is > 0 then, we have to move right side of the array and so, we will increment the i
When we find the sum == 0 then we can print the j and i index and return or break the loop.
And so, It's complete in a linear time. As well we don't need to use any other data structure as well.
Another solution to this problem could be:
1. Calculate sum for entire array
2. Now follow following formula to get the largest subarray with sum zero:
Math.max(find(a,l+1,r,sum-a[l]), find(a,l,r-1,sum-a[r]));
where l=left index, r= right index, initially their value=0 and a.length-1
Idea is simple, max size we can get with sum=0, is the size of array then we start skipping elements from left and right recursively, the moment we get sum=0 we stop. Below is the code for same:
static int find(int a[]) {
int sum =0;
for (int i = 0; i < a.length; i++) {
sum = sum+a[i];
}
return find(a, 0, a.length-1, sum);
}
static int find(int a[], int l, int r, int sum) {
if(l==r && sum>0) {
return 0;
}
if(sum==0) {
return r-l+1;
}
return Math.max(find(a,l+1,r,sum-a[l]), find(a,l,r-1,sum-a[r]));
}
Hope this will help.
int v[DIM] = {2, -3, 1, 2, 3, 1, 4, -6, 7, -5, -1};
int i,j,sum=0,counter=0;
for (i=0; i<DIM; i++) {
sum = v[i];
counter=0;
for (j=i+1; j<DIM;j++) {
sum += v[j];
counter++;
if (sum == 0) {
printf("Sub-array starting from index %d, length %d.\n",(j-counter),counter +1);
}
}
}