Random generator without repeated result - algorithm

I need to put the numbers from low to high in an array randomly.
For example given: low = 10, high = 15 a result like [ 12, 13, 10, 14, 11] is good.
This is a simple algorithm: iterate from low to high and try to fill in the empty slots on an array.
const low = 1000
const high = 1010
const diff = high - low
const arr = new Array(diff)
for (var i = low; i < high; i++) {
let success = false
while(!success) {
const index = Math.floor(Math.random() * diff)
if (arr[index] === undefined) {
arr[index] = i
success = true
}
console.log(`${index} was ${success ? 'available' : 'taken'}`)
}
}
console.log(arr)
The problem is: in the end where most of the elements are filled, it is harder to find an unoccupied slot in the array.
My question is: is there an algorithm that constantly generates unique new numbers until all the numbers are consumed?
Another way to think about it is an algorithm that shuffles an array the most efficient and quickest way.

Instead of generating "random" numbers, generate a list of the numbers and shuffle it "randomly" by using something like Fisher-Yates Shuffle:
function getRandomArray(min, max) {
return shuffle([...Array(max - min).keys()].map(i => i + min));
}
function shuffle(array) {
var m = array.length, t, i;
while (m) {
i = Math.floor(Math.random() * m--);
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
var randomArr = getRandomArray(10, 15);
console.log(randomArr);

Another implementation of Fisher-Yates Shuffle:
const low = 1000
const high = 1010
const delta = high - low
const arr = [...new Array(delta)]
arr.forEach((value, index, arr) => arr[index] = index + low)
const result = []
while (arr.length > 0) {
const index = Math.floor(Math.random() * arr.length)
result.push(arr[index])
arr.splice(index, 1)
}
console.log(result)

For someone looking this in java, just use Collections API.
We have:
Collections.shuffle(yourOriginalArray);

Related

Hackerrank The subarray sums question - time out test cases

Here is one question from hackerrank, I have a solution but there is some testcase failed because time limit exceeded. I don't know the better solution for it.
Find Sum of elements in a subarray (if in subarray has 0, sum = sum + number x)
input:
numbers: main array(1-indexed)
queries:
array of query: left index, right index, number x(0-indexed)
output:
array of sum corresponding with queries.
my solution on C++ code:
vector<long> findSum(vector<int>numbers, vector<vector<int>> queries)
{
vector<long>result;
long sum = 0;
int count = 0;
for(auto i : queries)
{
sum = 0;
count = 0;
int l = i[0] - 1;
int r = i[1]-1;
int x = i[2];
for(int j =l; j<r;j++)
{
sum+=numbers[j]==0?x:numbers[j];
}
result.push_back(sum);
}
return result;
}
As suggested by #Annity, you need to maintain two arrays:
Sum of all numbers so far. At any point of the index, it should have the sum of all previous numbers.
Same as above but it should have the total count of all previous Zeros.
You should avoid nested loops to reduce time complexity. Here is a solution in javascript:
function  findSum(numbers,  queries)  {
let  result  =   [];    
let  subArraySum  =   [];    
let  countZero  =  numbers[0]  ==  0  ?  1  :  0;    
let  zeroArr  =   [];    
zeroArr[0] =  countZero;    
subArraySum[0]  =  numbers[0];    
for (let  i = 1;  i <=  numbers.length - 1;  i++)  {               
if (numbers[i]  ==  0) {            
countZero++;            
zeroArr[i]  =  countZero;        
} 
else  {            
zeroArr[i]  =  countZero;         
}         
subArraySum[i]  = subArraySum[i - 1]  +  numbers[i];    
}    
for (let  q  of  queries)  {            
if (q.length  ==  3)  {            
let  i  =  q[0];            
let  j  =  q[1];            
let  x  =  q[2];            
let  sum  =  0;                       
sum  =  subArraySum[j - 1] - ((i - 2  <  0 )  ?  0  :  subArraySum[i - 2]);             
sum  =  sum  +  (zeroArr[j - 1] - ((i - 2  <  0 )  ?  0  :  zeroArr[i - 2])) * x;            
result.push(sum);        
}                  
}    
return  result;
}
console.log(findSum([5, 10, 15], [
[1, 2, 5]
]))
console.log(findSum([0, 10, 15], [
[1, 2, 5]
]))
Here's the solution that occurred to me.
You need to create two new arrays - one for the sums and one for the number of zeroes. Eg. sums[] and zeroes[].
In these two arrays you will store the value for the sum and the number of zeroes from the first element to the current. This is how it goes:
Loop through all of the numbers.
For each number with index i save in sums[i] the cumulative sum of all the elements from the first to the current and in zeroes[i] - the number of zeroes from the first element to the current.
Then loop through all of the queries.
For every query calculate the sum:
You take the sum from the sums array for the element with the right index and deduct the sum for the element before the left index.
(sum = sums[r] - sums[l-1])
If you deduct the count of zeroes in the element before the left index from the number in the element on the right index - you will get the number of zeroes in the interval.
(zero = zeroes[r] - zeroes[l-1])
Then multiply it by the third element in the query and add it to the sum.
And this is how you have the sum for the query.
this is in python
tempRes=0
temp = []
for b in range(len(queries)):
for k in range(queries[b][0]-1,queries[b][1]):
if numbers[k] == 0:
tempRes = tempRes + queries[b][2]
tempRes = tempRes + numbers[k]
temp.append(tempRes)
tempRes = 0
return temp
Your code takes a linear time per query. Invest in a linear time once to precompute an array of partial sums. Then each query will be answered in a constant time.
public static List<Long> findSum(List<Integer> numbers, List<List<Integer>> queries) {
// Write your code here
ArrayList<Long> arr = new ArrayList<>();
for(int i = 0; i < queries.size(); i++) {
int sum = 0;
for(int j = queries.get(i).get(0) - 1; j <= queries.get(i).get(1) - 1; j++) {
if(numbers.get(j) == 0){
sum += queries.get(i).get(2);
} else {
sum += numbers.get(j);
}
}
arr.add((long)sum);
sum = 0;
}
return arr;
}
The logic tries to sum each index with the last index.
But initializes the first index with 0.
The same with counting the zero.
After that, just subtract the left side with the desired index.
Also with the zero value in the index, but multiplid by the queries.
There you have it. I can't post the answer.
JS Solution:
There are two methods to solve this problem (Brute force Solution [Nested Loop]) and that's the method that responds with a timeout error throughout the execution of the test, you need to solve it with another time complexity, here is my answer 1st method O(N^2) and then 2nd method Optimized to be O(N) to solving the timeout error.
Answers in JavaScript wish it helps you.
/*
-- Brainstorming --
Have 1-indexed Array [numbers] of length n;
Have numbers of queries (q). [2D Array]
Each Query => [startIdx i, endIdx r, number x]
Find => Sum of numbers between indexes i and r (both included)
if zero occured in range add x instead of it.
*/
// 1st Method: Brute force Solution [Nested Loop]
function findSum(numbers, queries) {
const sum = new Array(queries.length).fill(0);
for (let i = 0; i < queries.length; i++) {
// let j = queries[i][0] - 1 Cause numbers 1-index not 0
for (let j = queries[i][0] - 1; j < queries[i][1]; j++) {
if (numbers[j] === 0) {
sum[i] += queries[i][2];
} else {
sum[i] += numbers[j];
}
}
}
return sum;
}
// 2nd Method: The Optimized Solution Single Loop
function findSum(numbers, queries) {
const sums = [];
const subArraySum = [];
const zerosArr = [];
let zerosCount = 0;
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] === 0) {
zerosCount++;
zerosArr[i] = zerosCount;
} else {
zerosArr[i] = zerosCount;
}
subArraySum[i] = numbers[i] + (subArraySum[i - 1] || 0);
}
for (let q of queries) {
const i = q[0] - 1;
const r = q[1] - 1;
const x = q[2];
let finalSum = subArraySum[r] - (subArraySum[i - 1] || 0) + (zerosArr[r] - (zerosArr[i - 1] || 0)) * x;
sums.push(finalSum);
}
return sums;
}
console.log("1st Test: " + findSum([5,10,10], [[1,2,5]])) // 15
console.log("2nd Test: " + findSum([-5,0], [ [2, 2 ,20] , [1,2,10]])) // 20 , 5
console.log("3rd Test: " + findSum([-1,-1,1,-4,3,-3,-4], [ [1, 4 ,2]])) // -5
console.log("4th Test: " + findSum([1000000000], [[1, 1,100]]))// 1000000000
console.log("5th Test: " + findSum([-1000000000], [[1, 1,100]]))// -1000000000
Try this(in javascript):
function findSum(numbers, queries) {
// Write your code here
let sumArr = [];
for (let i = 0; i < queries.length; i++) {
let sum = 0;
let start = queries[i][0];
let end = queries[i][1] + 1;
let x = queries[i][2];
const newArr = numbers.slice(start, end);
newArr.forEach((item) => {
if (item === 0) {
sum = sum + x;
}
sum = sum + item;
});
sumArr.push(sum);
}
return sumArr;
}
#!/usr/bin/python3
def solution(numbers, queries):
if not isinstance(numbers, list) and not isinstance(queries, list):
return
result = []
total = 0
for query in queries:
if len(query) == 3:
start = query[0]
end = query[1]
additional = query[2]
selection = numbers[start-1:end]
has_zeros = False
for el in selection:
if el == 0:
has_zeros = True
print(f"has_zeros: {has_zeros}")
print(f"selection: {selection}")
total = sum(selection)
if has_zeros:
total += additional
result.append(total)
return result
if "__main__" == __name__:
# 15
_input = [5, 10, 10]
_queries = [[1], [3], [1, 2, 5]]
print(f"input: {_input}")
print(f"queries: {_queries}")
_output = solution(_input, _queries)
print(f"ouput: {_output}")
Solution in python3 :
def findSum(numbers, queries):
a = [0]
b = [0]
for x in numbers:
a.append(a[-1] + x)
b.append(b[-1] + (x == 0)) if in subarray has 0, sum = sum + number x)
return [a[r] - a[l - 1] + x * (b[r] - b[l - 1]) for l, r, x in queries]

Super Ugly Number

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.

finding max and min in a stack and swap it without disturbing the other elements

Example if you have a stack
2
48
1
32
24
12
60
Then after operation it should look like
2
48
60
32
24
12
1
Here is a much better Javascript immplementation:
var stack = [2, 48, 1, 32, 24, 12, 60];
var minPos = stack.indexOf(stack.reduce(function (a, b) { return a <= b ? a : b; }));
var maxPos = stack.indexOf(stack.reduce(function (a, b) { return a >= b ? a : b; }));
stack[minPos] = stack.splice(maxPos, 1, stack[minPos])[0];
Other than the line to set-up an example stack, this approach does 3 things:
Find the position in the array of the 'minimum' number. A reduce function is used to iterate over the array, reducing the array to a single result, which represents the smallest number (See the JS Array.reduce method).
Find the position in the array of the 'maximum' number. This is done similar to the above, but with a reduce function that results in the highest number.
Using the positions we found for 'min' and 'max', swap the elements at these positions in the array.
Here is a JS implementation of a solution.
var myStack = [ 2, 48, 1, 32, 24, 12, 60 ];
var posMax = 0;
var maxValue = myStack[0];
var posMin = 0;
var minValue = myStack[0];
var tempStack = [ ]; // will be constructed, but in the reverse order.
var counter = 0;
do {
var tempElement = myStack.pop();
if(tempElement > maxValue) {
posMax = counter;
maxValue = tempElement;
}
if(tempElement < minValue) {
posMin = counter;
minValue = tempElement;
}
tempStack.push(tempElement);
counter++;
} while(myStack.length != 0);
// Reverse the order of the temp Stack
var tempStack2 = [];
do {
tempStack2.push(tempStack.pop());
} while (tempStack.length != 0)
tempStack = tempStack2;
// Constructing the returned Stack.
var newStack = [];
counter = 0;
do
{
var tempElement = tempStack.pop();
if(counter !== posMin && counter !== posMax) {
newStack.push(tempElement);
}
if(counter === posMax) {
newStack.push(minValue);
}
if(counter === posMin) {
newStack.push(maxValue);
}
counter++;
} while(tempStack.length != 0);
// Reverse the order of the new Stack
var result = [];
do {
result.push(newStack.pop());
} while (newStack.length != 0);
console.log("Final:" + result);

Finding out the minimum difference between elements in an array

I have an integer array with some finite number of values. My job is to find the minimum difference between any two elements in the array.
Consider that the array contains
4, 9, 1, 32, 13
Here the difference is minimum between 4 and 1 and so answer is 3.
What should be the algorithm to approach this problem. Also, I don't know why but I feel that using trees, this problem can be solved relatively easier. Can that be done?
The minimum difference will be one of the differences from among the consecutive pairs in sorted order. Sort the array, and go through the pairs of adjacent numbers looking for the smallest difference:
int[] a = new int[] {4, 9, 1, 32, 13};
Arrays.sort(a);
int minDiff = a[1]-a[0];
for (int i = 2 ; i != a.length ; i++) {
minDiff = Math.min(minDiff, a[i]-a[i-1]);
}
System.out.println(minDiff);
This prints 3.
You can take advantage of the fact that you are considering integers
to make a linear algorithm:
First pass:
compute the maximum and the minimum
Second pass:
allocate a boolean array of length (max - min + 1), false initialized,
and change the (value - min)th value to true for every value in the array
Third pass:
compute the differences between the indexes of the true valued entries of the boolean array.
While all the answers are correct, I wanted to show the underlying algorithm responsible for n log n run time. The divide and conquer way of finding the minimum distance between the two points or finding the closest points in a 1-D plane.
The general algorithm:
Let m = median(S).
Divide S into S1, S2 at m.
δ1 = Closest-Pair(S1).
δ2 = Closest-Pair(S2).
δ12 is minimum distance across the cut.
Return δ = min(δ1, δ2, δ12).
Here is a sample I created in Javascript:
// Points in 1-D
var points = [4, 9, 1, 32, 13];
var smallestDiff;
function mergeSort(arr) {
if (arr.length == 1)
return arr;
if (arr.length > 1) {
let breakpoint = Math.ceil((arr.length / 2));
// Left list starts with 0, breakpoint-1
let leftList = arr.slice(0, breakpoint);
// Right list starts with breakpoint, length-1
let rightList = arr.slice(breakpoint, arr.length);
// Make a recursive call
leftList = mergeSort(leftList);
rightList = mergeSort(rightList);
var a = merge(leftList, rightList);
return a;
}
}
function merge(leftList, rightList) {
let result = [];
while (leftList.length && rightList.length) {
// Sorting the x coordinates
if (leftList[0] <= rightList[0]) {
result.push(leftList.shift());
} else {
result.push(rightList.shift());
}
}
while (leftList.length)
result.push(leftList.shift());
while (rightList.length)
result.push(rightList.shift());
let diff;
if (result.length > 1) {
diff = result[1] - result[0];
} else {
diff = result[0];
}
if (smallestDiff) {
if (diff < smallestDiff)
smallestDiff = diff;
} else {
smallestDiff = diff;
}
return result;
}
mergeSort(points);
console.log(`Smallest difference: ${smallestDiff}`);
I would put them in a heap in O(nlogn) then pop one by one and get the minimum difference between every element that I pop. Finally I would have the minimum difference. However, there might be a better solution.
This is actually a restatement of the closest-pair problem in one-dimension.
https://en.wikipedia.org/wiki/Closest_pair_of_points_problem
http://www.cs.umd.edu/~samir/grant/cp.pdf
As the Wikipedia article cited below points out, the best decision-tree model of this problem also runs in Ω(nlogn) time.
sharing the simplest solution.
function FindMin(arr) {
//sort the array in increasing order
arr.sort((a,b) => {
return a-b;
});
let min = arr[1]-arr[0];
let n = arr.length;
for (var i=0;i<n;i++) {
let m = arr[i+1] - arr[i];
if(m < min){
m = min;
}
}
return m; // minimum difference.
}
The given problem can easily be solved in O(n) time. Look at the following code that I wrote.
import java.util.Scanner;
public class Solution {
public static void main(String [] args) {
Scanner input = new Scanner(System.in);
int i, minDistance = 999999;
boolean flag = false;
int capacity = input.nextInt();
int arr[] = new int[capacity];
for (i = 0; i < capacity; i++) {
arr[i] = input.nextInt();
}
int firstElement = input.nextInt();
int secondElement = input.nextInt();
int prev = 0;
for (i = 0; i < capacity; i++) {
if (arr[i] == firstElement || arr[i] == secondElement) {
prev = i;
break;
}
}
for (; i < capacity; i++) {
if(arr[i] == firstElement || arr[i] == secondElement) {
if(arr[i] != arr[prev] && minDistance > Math.abs(i - prev)) {
minDistance = Math.abs(i - prev);
flag = true;
prev = i;
} else {
prev = i;
}
}
}
if(flag)
System.out.println(minDistance);
else
System.out.println("-1");
}
}
For those of you who are looking for a one-line python answer (more or less), these are 2 possible solutions:
Python >= 3.10
l = sorted([4, 9, 1, 32, 13])
min(map(lambda x: x[1] - x[0], pairwise(l)))
From Python 3.10 you can use pairwise() that takes an iterable and returns all consecutive pairs of it. After we sort the initial list, we just need to find the pair with the minimum difference.
Python < 3.10
l = sorted([4, 9, 1, 32, 13])
min(map(lambda x: x[1] - x[0], zip(l[:-1], l[1:])))
In this case, we can reproduce the pairwise() method behavior1 using zip() with 2 slices of the same list so that consecutive elements are paired.
1. The actual implementation of pairwise() is probably more efficient in terms of space because it doesn't need to create 2 (shallow) copies of the list. In most cases, this should not be necessary, but you can use itertools.islice to iterate over the list without creating a copy of it. Then, you would write something like zip(islice(a, len(a) - 1), islice(a, 1, None)).
In Python 3 this problem can be simplified by using the module itertools which gives the combinations available for a list. From that list we can find the sum of each combination and find the minimum of those values.
import itertools
arr = [4, 9, 1, 32, 13]
if len(arr) > 1:
min_diff = abs(arr[0] - arr[1])
else:
min_diff = 0
for n1, n2 in itertools.combinations(arr, 2): # Get the combinations of numbers
diff = abs(n1-n2) # Find the absolute difference of each combination
if min_diff > diff:
min_diff = diff # Replace incase a least differnce found
print(min_diff)

Find all pairs of integers within an array which sum to a specified value

Design an algorithm to find all pairs of integers within an array which sum to a specified value.
I have tried this problem using a hash table to store entries for the sum of array elements, but it is not an efficient solution.
What algorithm can I use to solve this efficiently?
I don't see why the hash table approach is inefficient, at least in algorithm analysis terms - in memory locality terms admittedly, it can be quite bad. Anyway, scan the array twice...
First scan - put all the array elements in the hash table - O(n) total. Individual inserts are only amortized O(1), but a neat thing about how amortized analysis works means the O(n) is absolute - not amortized.
Second scan - check for (sum - current) in the hash table - O(n) total.
This beats the O(n log n) sort-and-search methods, at least in theory.
Then, note that you can combine the two scans into one. You can spot a pair as soon as you encounter the second of that pair during the first scan. In pseudocode...
for i in array.range
hashset.insert (array [i])
diff = sum - array [i]
if hashset.includes (diff)
output diff, array [i]
If you need positions of the items, use a hashmap and store item positions in it. If you need to cope with duplicates, you might need to store counts in a hashmap. For positions and duplicates, you might need a hashmap of start pointers for linked lists of positions.
This makes assumptions about the hash table implementation, but fairly safe ones given the usual implementations in most current languages and libraries.
BTW - combining the scans shouldn't be seen as an optimisation. The iteration overhead should be insignificant. Memory locality issues could make a single pass slightly more efficient for very large arrays, but the real memory locality issues will be in the hashtable lookups anyway.
IMO the only real reason to combine the scans is because you only want each pair reported once - handling that in a two-scan approach would be a bit more hassle.
If the array is sorted:
Let i = 0, j = end of array, sum = the value you are looking for,
then do:
If i+j = sum, then output (i,j).
If i+j < sum, then move i to the right one position.
If i+j > sum, then move j to the left one position.
Time complexity: O(n). Space complexity: O(1).
If the array is not sorted, there are a few ways to approach this problem:
Sort the array and then use the above approach.
HashMap:
Store all elements in a HashMap.
a+b=sum, so b=sum-a. For each element a of the array, look up b from the HashMap.
HashMap lookup takes amortized O(1).
Time complexity: O(n). Space complexity: O(n).
BitMap:
Iterate through the input to create a bitmap where each bit corresponds to an element value. Say the input is {2,5,8}, then we toggle the bitmap array's indices 2, 5 and 8 from binary 0 to 1. This takes O(1) per element, thus O(n) in total.
Go through the input again. We know b=sum-a, so for every element a in the input, look up its b, which can be done in O(1) since it's a bitmap index. This also takes O(n) in total.
Time complexity: O(n) + O(n) = O(n). Space complexity: bitmap space = O(n).
You don't even need to store all the elements in hashmap, and then scan. You can scan during the first iteration itself.
void foo(int[] A, int sum) {
HashSet<Integer> set = new HashSet<Integer>();
for (int e : A) {
if (set.contains(sum-e)) {
System.out.println(e + "," + (sum-e));
// deal with the duplicated case
set.remove(sum-e);
} else {
set.add(e);
}
}
}
How about sorting the array, then marching in from both ends?
Assume required sum = R
sort the array
for each number in the array A(n), do a binary search to find the number A(x) such that A(n) + A(x) = R
If you don't mind spending O(M) in space, where M is the sum you are seeking, you can do this in O(N + M) time. Set sums[i] = 1 when i <= M on a single pass over N, then check (sums[i] && sums[M-i]) on a single pass over M/2.
#include <iostream>
using namespace std;
#define MAX 15
int main()
{
int array[MAX] = {-12,-6,-4,-2,0,1,2,4,6,7,8,12,13,20,24};
const int find_sum = 0;
int max_index = MAX - 1;
int min_index = 0;
while(min_index < max_index)
{
if(array[min_index] + array[max_index-min_index] == find_sum)
{
cout << array[min_index] << " & " << array[max_index-min_index] << " Matched" << endl;
return 0;
}
if(array[min_index]+array[max_index-min_index] < find_sum)
{
min_index++;
//max_index++;
}
if(array[min_index]+array[max_index-min_index] > find_sum)
{
max_index--;
}
}
cout << "NO MATCH" << endl;
return 0;
}
//-12 & 12 matched
Implemented in Python 2.7:
import itertools
list = [1, 1, 2, 3, 4, 5,]
uniquelist = set(list)
targetsum = 5
for n in itertools.combinations(uniquelist, 2):
if n[0] + n[1] == targetsum:
print str(n[0]) + " + " + str(n[1])
Output:
1 + 4
2 + 3
We can use C++ STL map to solve this
void subsetSum(int arr[], int n, int sum)
{
map<int, int>Map;
for(int i=0; i<n; i++)
{
Map[arr[i]]++;
if(Map.count(sum-arr[i]))
{
cout<<arr[i]<<" "<<sum-arr[i]<<"\n";
}
}
}
Here is a solution witch takes into account duplicate entries. It is written in javascript and assumes array is sorted. The solution runs in O(n) time and does not use any extra memory aside from variable.
var count_pairs = function(_arr,x) {
if(!x) x = 0;
var pairs = 0;
var i = 0;
var k = _arr.length-1;
if((k+1)<2) return pairs;
var halfX = x/2;
while(i<k) {
var curK = _arr[k];
var curI = _arr[i];
var pairsThisLoop = 0;
if(curK+curI==x) {
// if midpoint and equal find combinations
if(curK==curI) {
var comb = 1;
while(--k>=i) pairs+=(comb++);
break;
}
// count pair and k duplicates
pairsThisLoop++;
while(_arr[--k]==curK) pairsThisLoop++;
// add k side pairs to running total for every i side pair found
pairs+=pairsThisLoop;
while(_arr[++i]==curI) pairs+=pairsThisLoop;
} else {
// if we are at a mid point
if(curK==curI) break;
var distK = Math.abs(halfX-curK);
var distI = Math.abs(halfX-curI);
if(distI > distK) while(_arr[++i]==curI);
else while(_arr[--k]==curK);
}
}
return pairs;
}
So here it is for everyone.
Start at both side of the array and slowly work your way inwards making sure to count duplicates if they exist.
It only counts pairs but can be reworked to
find the pairs
find pairs < x
find pairs > x
Enjoy and don't forget to bump it if its the best answer!!
A solution that takes into account duplicates and uses every number only one time:
void printPairs(int[] numbers, int S) {
// toMap(numbers) converts the numbers array to a map, where
// Key is a number from the original array
// Value is a count of occurrences of this number in the array
Map<Integer, Integer> numbersMap = toMap(numbers);
for (Entry<Integer, Integer> entry : numbersMap.entrySet()) {
if (entry.getValue().equals(0)) {
continue;
}
int number = entry.getKey();
int complement = S - number;
if (numbersMap.containsKey(complement) && numbersMap.get(complement) > 0) {
for (int j = 0; j < min(numbersMap.get(number),
numbersMap.get(complement)); j++) {
if (number.equals(complement) && numbersMap.get(number) < 2) {
break;
}
System.out.println(number, complement);
numbersMap.put(number, numbersMap.get(number) - 1);
numbersMap.put(complement, numbersMap.get(complement) - 1);
}
}
}
}
Hashtable solution, in Ruby (quite straightforward to understand):
value = 100
pairs = [1,99,5,95]
hash_of_pairs = {}
pairs.map! do |pair|
# Adds to hashtable the pair
hash_of_pairs[pair] = pair
# Finds the value the pair needs
new_pair = hash_of_pairs[value - pair]
# Returns the pair whenever the pair exists, or nil
[new_pair, pair] if !new_pair.nil?
end.compact! # Cleans up the array, removing all nil values
print pairs # [[1,99], [5,95]]
#Test
public void hasPairWithSum() {
assertFalse(hasPairWithSum_Ordered_Logarithmic(new int[] { 1, 2, 3, 9 }, 8));
assertTrue(hasPairWithSum_Ordered_Logarithmic(new int[] { 1, 2, 4, 4 }, 8));
assertFalse(hasPairWithSum_Ordered_Linear(new int[] { 1, 2, 3, 9 }, 8));
assertTrue(hasPairWithSum_Ordered_Linear(new int[] { 1, 2, 4, 4 }, 8));
assertFalse(hasPairWithSum_Unsorted_Linear(new int[] { 9, 1, 3, 2 }, 8));
assertTrue(hasPairWithSum_Unsorted_Linear(new int[] { 4, 2, 1, 4 }, 8));
assertFalse(hasPairWithSum_Unsorted_Quadratic(new int[] { 9, 1, 3, 2 }, 8));
assertTrue(hasPairWithSum_Unsorted_Quadratic(new int[] { 4, 2, 1, 4 }, 8));
}
private boolean hasPairWithSum_Ordered_Logarithmic(int[] data, int sum) {
for (int i = 0; i < data.length; i++) {
int current = data[i];
int complement = sum - current;
int foundIndex = Arrays.binarySearch(data, complement);
if (foundIndex >= 0 && foundIndex != i) {
return true;
}
}
return false;
}
private boolean hasPairWithSum_Ordered_Linear(int[] data, int sum) {
int low = 0;
int high = data.length - 1;
while (low < high) {
int total = data[low] + data[high];
if (total == sum) {
return true;
} else if (total < sum) {
low++;
} else {
high--;
}
}
return false;
}
private boolean hasPairWithSum_Unsorted_Linear(int[] data, int sum) {
Set<Integer> complements = Sets.newHashSet();
for (int current : data) {
if (complements.contains(current)) {
return true;
}
complements.add(sum - current);
}
return false;
}
private boolean hasPairWithSum_Unsorted_Quadratic(int[] data, int sum) {
for (int i = 0; i < data.length; i++) {
int current = data[i];
int complement = sum - current;
for (int j = 0; j < data.length; j++) {
if (data[j] == complement && i != j) {
return true;
}
}
}
return false;
}
Creating a hash table and then looking for value in it.
function sum_exist(num : number, arr : any[]) {
var number_seen = {};
for(let item of arr){
if(num - item in number_seen){
return true
}
number_seen[item] = 0;
}
return false;
}
Test case (using Jest)
test('Given a list of numbers, return whether any two sums equal to the set number.', () => {
expect(sum_exist(17 , [10, 15, 3, 7])).toEqual(true);
});
test('Given a list of numbers, return whether any two sums equal to the set number.', () => {
expect(sum_exist(16 , [10, 15, 3, 7])).toEqual(false);
});
#python 3.x
def sum_pairs(list_data, number):
list_data.sort()
left = 0
right = len(list_data)-1
pairs = []
while left < right:
if list_data[left]+list_data[right] == number:
find_pairs = [list_data[left], list_data[right]]
pairs.append(find_pairs)
right = right-1
elif list_data[left]+list_data[right] < number:
left = left+1
else:
right = right-1
return pairs

Resources