How do you take a number representing a list of items, and divide it into chunks, where the number of chunks is a power-of-two, AND where each chunk also has a power-of-two number of items (where size goes up to a max power of two, so 1, 2, 4, 8, 16, 32, 32 being the max)? Is this even possible?
So for example, 8 items could be divided into 1 bucket (power of two bucket) with 8 items (power of two items):
[8]
9 items could be:
[8, 1]
That works because both numbers are powers of two, and the size of the array is 2 (also a power of two).
Let's try 11:
[8, 2, 1]
Nope that doesn't work. Because the size of the array is 3 which is not a power of two, even though it adds to 11. How about this?
[4, 4, 2, 1]
That works! It's 4 elements which is a power of two.
[2, 2, 2, 1, 1, 1, 1, 1]
That also works, since there are 8 buckets (8 is a power of two), with 1 or 2 items each (each a power of two). But [4, 4, 2, 1] is better because it's shorter.
I guess an even better one (after getting comments) would be this, though I didn't see it the first time around:
[8, 1, 1, 1]
That one is short, and also starts with the largest number.
So following this pattern, here are some other numbers:
13:
[8, 1, 1, 1, 1, 1] // no, 6 not power of 2
[8, 2, 1, 1, 1] // no, 5 not power of 2
[8, 2, 2, 1] // yes, 4 is power of 2
[8, 4, 1] // no, 3 not power of 2
14:
[8, 2, 2, 2]
15:
[8, 4, 2, 1]
16:
[16]
18:
[16, 2]
200:
[32, 32, 32, 32, 32, 32, 4, 4]
When the size of the first layer of buckets in the bucket tree grows to longer than 32, then it nests. So take the number 1234 for example. This can be represented by 38 32's followed by 16 followed by 4.
[32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 16, 4]
But now the bucket size is 40 items long, which isn't a power of two AND it's greater than 32. So it should be nested! I can't quite visualize this in my head, so sorry if this isn't a perfect example, I think you can get the gist of what I mean though.
// the parent "x" is 2 in length
x = [a, b]
// child "a" is 32 in length
a = [32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32]
// child "b" is 8 in length
b = [32, 32, 32, 32, 32, 32, 16, 4]
Taken another layer up, say we have a very large number (I don't know what the minimum large number is) that requires another layer of nesting. What we can say about this layer is that, x will be 32 in length, but we will also have a y that is at least 1.
_x_ = [a, b, c, d, e, f, g, h,
i, j, k, l, m, n, o, p,
q, r, s, t, u, v, w, x,
y, z, a2, b2, c2, d2, e2, f2]
_y_ = [a3]
a = [32, 32, 32, ..., ?]
...
f2 = [32, ..., ?]
Then once we have _x_, _y_, _z_, ... 32 total of these, we build another layer on top.
What is an algorithm/equation that will take a number and divide it into this tree of buckets / item sizes that are all powers of two, up to a max (in this case, 32)?
A subgoal is to minimize the number of levels. There isn't a specific limit, but I am imagining no more than 1 million or very max 1 billion nodes in the entire runtime, so it seems like you'll only have 3 or 4 levels probably, I don't know exactly how to calculate it.
This is going to be used for array lookup. Essentially I am breaking apart a single, large, arbitrarily sized "contiguous" array into small contiguous chunks with size power-of-2 up to 32 in length. This balances lookup performance (i.e. fits within cpu cache), with memory fragmentation.
Update:
I think trying to incorporate this somehow to build up that nested tree I'm trying to describe will help. The last thing now missing is getting the nested arrays to be properly sized to power-of-two values...
The best I have been able to do so far is this:
console.log(spread(74))
console.log(spread(85))
console.log(spread(87))
console.log(spread(127))
console.log(spread(1279))
console.log(spread(12790))
console.log(spread(127901))
function spread(n) {
if (n == 0) {
return [0, 0, 0, 0, 0, 0]
}
let array = []
let r = split(n)
while (r[0] > 31) {
array.push([32, 0, 0, 0, 0, 0])
r[0] -= 32
}
array.push(r)
let s = sum(r)
if (!isPowerOf2(s)) {
let x = pow2ceil(s)
let i = 1
while (i < 5) {
if (r[i] > 1) {
i++
break
}
i++
}
if (i == 5) {
i = 0
}
main:
while (true) {
while (r[i]) {
r[i + 1] += 2
r[i]--
s += 1
if (s == x) {
break main
}
}
i++
}
}
if (array.length == 1) {
return array[0]
} else if (array.length < 33) {
return array
} else {
return divide(array, 32)
}
}
function sum(arr) {
let i = 0
arr.forEach(x => {
i += x
})
return i
}
function split(n) {
const r = [0, 0, 0, 0, 0, 0]
let u = 32
let i = 0
while (u > 0) {
while (n >= u) {
r[i]++
n -= u
}
i += 1
u >>= 1
}
return r
}
function isPowerOf2(v) {
return v && !(v & (v - 1))
}
function pow2floor(v) {
var p = 1;
while (v >>= 1) {
p <<= 1;
}
return p;
}
function pow2ceil(v) {
var p = 2
while (v >>= 1) {
p <<= 1
}
return p
}
function divide(data, size) {
const result = []
const upSize = data.length / size;
for (let i = 0; i < data.length; i += size) {
const chunk = data.slice(i, i + size);
result.push(chunk)
}
if (result.length > size) {
return divide(result, size)
}
return result;
}
It's always possible.
Start with the normal binary representation.
You get a number of summands that are all powers of 2.
So the problem is the number of summands is most of the times not a power of two.
You can always get an extra summand by splitting a power of 2 in 2 summand (also powers of 2). Only exception is 1.
So the question is there a case where not enough summand > 1 exists?
Answer: No
Worst case is we have n summand where n is a (power of 2)-1.
E.g. 3, 7,15, ...
Is we have 3 summand the smallest possible case is 1+2+4. We need 4 summand, so we must create 1 extra summand by splitting one of the summands >1 into two. e.g 1+1+1+4.
For bigger values the highest summand is always >= ceeling(value/2) and has at most ceeling(sqrt(value))+1 summands in binary representation.
ceeling(value/2) grows much faster than sqrt(value).
So we have with increasing values always plenty of summands to split to reach the power of 2 summands goal.
Example: value= 63
Binary representation: 32+16+8+4+2+1 (6 summands)
Highest summand is 32 (at least value/2) (which can be split in any number of summands (all powers of 2) up to 32 summands.
We need at most ceeling(sqrt(63))+1 = 8 summands to reach a power of 2 summands.
So we need 2 extra summands for our 32+16+8+4+2+1
Take any summand >1 and split it in two summands (powers of 2)
e.g 32 = 16+16
=> 16+16+16+8+4+2+1 (7 summands)
do it again (because we needed 2 extra summands).
Take any summand >1 e.g. 4 and split ist 2+2=4
=> 16+16+16+8+2+2+2+1 (8 summands)
Here is a possible algorithm:
Check the lowest 5 bits of the input number n and generate the corresponding powers of 2 in an array. So for instance for n = 13 we get [1, 4, 8]
Divide n by 32 ignoring the above-mentioned bits (floor).
Add to the above array as many values of 32 as n modulo 32. So for example for input = 77 we get [1, 4, 8, 32, 32]
Most of the times this array will have a length that does not exceed 32, but it could go up to 36: [1, 2, 4, 8, 16, 32, ..., 32]. If that happens, extract 16 values from the end of the array and store them in a "carry": this carry will be processed later. So not considering this potential carry, we ensure we end up with an array that is not longer than 32.
Then perform a split in halves of the greatest value in the array (thereby growing the array with one unit) until the array's length is a power of 2. For instance, for the case of 77 we'll have a few of such iterations in order to get [1, 4, 8, 8, 8, 16, 16, 16]
Divide n again by 32 ignoring the remainder (floor).
Consider again n modulo 32. If this is non-zero we have found summands of 32*32, so we create a new array [32, ..., 32] for each of those, and combine that with the previously established array into a new tree. So for instance for 1037, we could get
[
[1,4,4,4],
[32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32]
]
If there is room to add a potential carry (i.e. the top level array does not have a length of 32), then do so.
If the length of the array is not yet a power of 2, apply a similar algorithm as previously mentioned, although now a split in half concerns arrays instead of primitive values.
Repeat this division by 32 to identify even higher nested summands, so these are complete 32*32*32 trees, then in the next iteration, these are complete 324 trees, etc, until all of n is accounted for.
At the end, check if the carry is still there and could not yet be added somewhere: if this is the case add an extra level to the tree (at the top) to combine the achieved result with this carry, so they are siblings in an array of 2.
Implementation
Here is an interactive snippet: type a number and the resulting tree will be displayed in real time. Note that the nested tree is really created in this implementation and will consume quite some memory, so to keep the response times acceptable in JavaScript, I have limited the allowed input to numbers with 7 digits, but in theory the only limit is memory and floating point precision (which in this script is guaranteed up to 253).
// Utility functions
const sum = arr => arr.reduce((a, b) => a+b, 0);
const powersOf2andZero = [0,1,2,4,8,16,32];
const clone = tree => JSON.parse(JSON.stringify(tree));
function createTree(n) {
let tree = [];
let carry = null;
// Isolate 5 least significant bits
for (let pow of [1, 2, 4, 8, 16]) if (n & pow) tree.push(pow);
n = Math.floor(n / 32);
for (let i = n % 32; i > 0; i--) tree.push(32);
// This array could have more than 32 values, up to 36.
// If that happens: remove 16 occurrences of 32, and consider this as carry-over for later treatment.
if (tree.length > 32) carry = tree.splice(-16); // pop off 16 x 32s.
// Make the array length a power of 2 by splitting the greatest value (repeatedly)
let j = tree.length;
while (!powersOf2andZero.includes(tree.length)) {
if (j >= tree.length) j = tree.indexOf(tree[tree.length - 1]); // first occurrence of greatest
// Split greatest value into 2; keep list sorted
tree.splice(j, 1, tree[j] / 2, tree[j] / 2); // delete, and insert twice the half at same spot
j += 2;
}
// Isolate and count factors of 32, 32², 32³, ...etc.
// Add a superiour level in the tree for each power of 32 that is found:
n = Math.floor(n / 32);
let template = 32;
while (n) {
if (tree.length > 1) tree = [tree]; // nest
if (n % 32 < 31 && carry !== null) { // we have room to dump the carry here
tree.push(carry);
carry = null;
}
template = Array(32).fill(template); // nest the template tree, "multiplying" by 32.
for (let i = n % 32; i > 0; i--) tree.push(clone(template));
if (tree.length === 1 && typeof tree[0] !== "number") tree = tree[0]; // Eliminate useless array wrapper
// Turn this top level into a length that is a power of 2 by splitting the longest array (repeatedly)
let j = tree.length;
while (!powersOf2andZero.includes(tree.length)) {
if (j >= tree.length) j = tree.findIndex(elem => elem.length === tree[tree.length - 1].length);
// Split longest array into 2; keep list sorted
let size = tree[j].length / 2;
tree.splice(j, 1, tree[j].slice(0, size), tree[j].slice(size)); // delete, and insert twice the half
j += 2;
}
n = Math.floor(n / 32);
}
// Is the carry still there? Then we cannot avoid adding a level for it
if (carry) return [tree, carry];
return tree;
}
// I/O handling
let input = document.querySelector("input");
let output = document.querySelector("pre");
(input.oninput = function () {
let n = +input.value;
if (isNaN(n) || n % 1 !== 0 || n < 1 || n > 9999999) {
output.textContent = "Please enter an integer between 1 and 9999999";
} else {
let tree = createTree(n);
output.textContent = pretty(tree);
}
})();
function pretty(tree) {
return JSON.stringify(tree, null, 2)
.replace(/\[\s*\d+\s*(,\s*\d+\s*)*\]/g, m => m.replace(/\s+/g, ""))
.replace(/\b\d\b/g, " $&");
}
pre { font-size: 8px }
n: <input type="number" value="927">
<pre></pre>
(Note, the following answers the restriction on part size and the restriction on the number of parts being a power of 2. I missed the part about the number of parts also being restricted, indicating nesting. I'll try to get to that next.)
A simple proof that's also a method is that our minimal number of parts, MIN, is M = floor(N / max_power_of_2) plus the number of set bits in the binary representation of N - M*max_power_of_2; and the maximal number of parts, MAX, is N, where each part is 1.
Each time we divide one of the powers of 2, P, in the power-of-two representation of M (which starts as some count of max_power_of_2) or N-M*max_power_of_2, we have one count less of P, and two more of P/2, another power of 2. This action adds just one part to the partition, meaning we can represent any number of parts between MIN and MAX.
Greedy JavaScript code:
function f(n, maxP){
const maxPowerOf2 = 1 << maxP;
const m = ~~(n / maxPowerOf2);
const A = new Array(maxP + 1).fill(0);
A[maxP] = m;
let nm = n - m * maxPowerOf2;
let p = 0;
let bitCount = 0;
while (nm){
if (nm & 1){
bitCount += 1;
A[p] = 1;
}
nm >>= 1;
p += 1;
}
const min = m + bitCount;
let target = 1;
while (target < min)
target *= 2;
if (target > n)
return -1;
if (target == min)
return A.map((c, p) => [1 << Number(p), c]);
if (target == n)
return [n];
// Target is between MIN and MAX
target = target - min;
let i = m ? maxP : p;
while (target && i > 0){
if (!A[i]){
i -= 1;
continue;
}
const max = Math.min(target, A[i]);
A[i] -= max;
A[i-1] += 2*max;
target -= max;
i -= 1;
}
return target ? -1 : A.map((c, p) => [1 << Number(p), c]);
}
var ns = [74, 85, 87, 127, 1279, 12790, 127901, 63];
var maxP = 5;
for (let n of ns){
let result = f(n, maxP);
let [_n, numParts] = result.reduce(([_n, numParts], [p, c]) => [_n + p * c, numParts + c], [0, 0]);
console.log(n, maxP);
console.log(JSON.stringify(result));
console.log(JSON.stringify([_n, numParts]));
console.log('');
}
I'm writing an algorithm that finds the number of possible sums from an array that contains unique values, and a second array that contains the quantity of each corresponding value in the first array. For example, the pair [10, 20, 50] and [1, 2, 1] indicates that the total number of elements that I am combining is actually [10, 20, 20, 50], because there are two instances of the number 20.
My algorithm is currently passing every test except one, and I cannot for the life of me figure out why, since it is passing other, more complicated pairings. Here is my algorithm so far:
function possibleSums(values, quantity) {
const sums = new Set([]);
//my recursive function that finds all possible combinations moving
//down from a specific starting index in the valueArrray:
const combinations = (valueArray, countArray, position, currentSum) => {
if (currentSum > 0) sums.add(currentSum);
for(let i = position; i < valueArray.length; i++){
if (countArray[i] === 0){
continue;
}
currentSum += valueArray[i];
//reduce the count of that value that is still available
countArray[i]--;
//send off a recursive call to find the sum with the next
//available value
combinations(valueArray, countArray, i, currentSum);
//return the original count since `i` is increasing past
//the current value's location in the valueArray
countArray[i]++;
}
}
for (let i = 0; i < values.length; i++){
//start the recursive function calls at each index in the value array
combinations(values, quantity, i, 0)
}
return sums.size
}
This algorithm passes array pairs like :
[3, 1, 1] and [111, 84, 104] with the expected output of 521
[1, 1, 1, 1, 1] and [9, 19, 18, 12, 19] with the expected output of 77
[1, 2, 3] and [2, 3, 10000] with the expected output of 30008
but is failing
[10, 50, 100, 500] and [5, 3, 2, 2] , outputting 96 when the expected output is 122
Can anyone spot what I am missing in my logic?
122 expected output is not too big a test case for logging :)
Let's log the parameters:
...
const combinations = (valueArray, countArray, position, currentSum) => {
console.log(countArray, position, currentSum)
if (currentSum...
We see this, which makes sense:
[ 0, 0, 0, 0 ] 3 1400
But then we also see:
[ 0, 0, 1, 0 ] 3 1400
[ 0, 1, 0, 0 ] 3 1400
...
[ 1, 1, 1, 0 ] 3 1400
which don't.
Changing the current argument during the iteration seems to be affecting the variable during other calls.
Changing
currentSum += valueArray[i];
...
combinations(valueArray, countArray, i, currentSum);
to
//currentSum += valueArray[i];
...
combinations(valueArray, countArray, i, currentSum + valueArray[i]);
seems to do the trick.
I was told in an interview to write a program for implementing merge sort on the concept of divide and conquer.
I wrote the below program,
var myGlobalArray = undefined;
myGlobalArray = [8,4,17,2,1,32];
example01(myGlobalArray);
myGlobalArray = [48,14,17,2,11,132];
example01(myGlobalArray);
myGlobalArray = [45,14,5,2,1,12];
example01(myGlobalArray);
myGlobalArray = [45,-14,-5,2,1,-12];
example01(myGlobalArray);
myGlobalArray = [38,27,43,3,9,82,10];
example01(myGlobalArray);
function example01(myArray){
var mainArray = [];
createSubArray(myArray,0);
mainArray = mergeArrays(mainArray);
console.log(mainArray[0]);
// creates an array which contains n arrays for n numbers present in myarray
// i.e. if array = [ 34, 1, 27, 3 ] that the below method will return
// [ [34], [1], [27], [3] ]
function createSubArray(subArray,index){
var localArray = [];
if(subArray[index] !== undefined){
localArray.push(subArray[index]);
mainArray.push(localArray);
createSubArray(subArray,++index);// performs division recursively
}
}//createSubArray
// merge the arrays present i.e.
// if gblArray = [ [2,5], [1,7] ]
// then the below method will return
// an merged array [ [1, 2, 5, 7] ]
function mergeArrays(gblArray){
var mergedArrays = [],
main_array = gblArray,
arr = [],
counter = 0,
nextCounter = 0;
do{
while(counter < main_array.length){
nextCounter = counter + 1;
if(main_array[nextCounter] !== undefined){
arr = mergeAndSort(main_array[counter],main_array[nextCounter]);
mergedArrays.push(arr);
}else{
mergedArrays.push(main_array[counter]);
}
counter = nextCounter + 1;
}
main_array = mergedArrays;
mergedArrays = [];
counter = 0;
nextCounter = 0;
}while(main_array.length > 1);
return main_array;
}//mergeArrays
// merges two array and sorts i.e.
// if array1 = [23,1] and array2 = [4,12] than
// the below method returns [1,4,12,23]
function mergeAndSort(array1,array2){
var array2Counter = 0,
array1Counter = 0,
mergedArray = [];
while(array2Counter < array2.length && array1Counter < array1.length){
if(array2[array2Counter] < array1[array1Counter]){
mergedArray.push(array2[array2Counter]);
array2Counter++;
}else{
mergedArray.push(array1[array1Counter]);
array1Counter++;
}
}
while(array1Counter < array1.length){
mergedArray.push(array1[array1Counter]);
array1Counter++;
}
while(array2Counter < array2.length){
mergedArray.push(array2[array2Counter]);
array2Counter++;
}
return mergedArray;
} //mergeAndSort
}//example01
If I run the above code,
the output is
[ 1, 2, 4, 8, 17, 32 ]
[ 2, 11, 14, 17, 48, 132 ]
[ 1, 2, 5, 12, 14, 45 ]
[ -14, -12, -5, 1, 2, 45 ]
[ 3, 9, 10, 27, 38, 43, 82 ]
But by looking at my above implemented merge-sort program, the inteviewer said that if doesn't follows divide and conquer concept.
I tried to convince him that method "mergeArrays" and "mergeAndSort"
do the divide and conquer. But he didn't agreed.
Where am I going wrong ?
The definition of divide and conquer on Wikipedia is:
an algorithm design paradigm based on multi-branched recursion. A divide and conquer algorithm works by recursively breaking down a problem into two or more sub-problems of the same or related type, until these become simple enough to be solved directly. The solutions to the sub-problems are then combined to give a solution to the original problem.
Your solution does divide, and does combine the solutions to give the final solution, but it does not perform the divisions recursively, making the sub problems gradually smaller.
Edit: you do use recursion, but not in the way intended here. Your recursion is tail-recursion, chopping off the smallest unit (they are not gradually getting smaller), and repeating that chopping via a chain of recursive calls, which could just as easily be performed in a loop.
Your solution is a bottom-up approach, while divide and conquer is commonly understood as a top-down method. Although both methods are valid implementations of merge sort, strictly speaking, only one of them uses the divide and conquer paradigm.
But in a broader interpretation, divide and conquer can just as well be bottom-up, relaxing some of the requirements in the definition quoted above. So this may in the end be a matter of opinion.
I have three sorted array I need to find top five "5" element from these array .I am able to find first two element largest element .how I will find other ?
can you suggest how we can find other 3 element ?
here is my code
var maxArray=[];
var array1=[2,7,12,23,40,44,67,88,102]
var array2=[3,12,14,17,23,40,41,67,108]
var array3=[8,12,23,40,59,86,119,130]
var firstMax=array1[array1.length-1];
var secondMax=array2[array2.length-1];
alert(array1[array1.length-1]);
if(array1[array1.length-1]>array2[array2.length-1] && array1[array1.length-1]>array3[array3.length-1]){
maxArray.push(array1[array1.length-1]) ;
firstMax=array1[array1.length-1];
if(array2[array2.length-1]>array3[array3.length-1]){
secondMax=array2[array2.length-1];
}else {
secondMax=array3[array3.length-1];
}
}else if(array2[array2.length-1]>array1[array1.length-1]&& array2[array2.length-1]>array3[array3.length-1]){
maxArray.push(array1[array2.length-1])
firstMax=array2[array2.length-1];
if(array1[array1.length-1]>array3[array3.length-1]){
secondMax=array1[array1.length-1];
}else {
secondMax=array3[array3.length-1];
}
}else{
maxArray.push(array3[array3.length-1])
firstMax=array3[array3.length-1];
if(array2[array2.length-1]>array1[array1.length-1]){
secondMax=array2[array2.length-1];
}else {
secondMax=array1[array1.length-1];
}
}
maxArray.push(secondMax)
alert(maxArray)
fiddle
http://jsfiddle.net/9vsjm8uh/
jsFiddle (yep, even better without jQuery, thanks #Rajacsp)
var array1 = [2, 7, 12, 23, 40, 44, 67, 88, 102]
var array2 = [3, 12, 14, 17, 23, 40, 41, 67, 108]
var array3 = [8, 12, 23, 40, 59, 86, 119, 130]
var flatArray = array1.concat(array2).concat(array3);
flatArray.sort(function sortNumber(a, b) { return b - a; });
var maxArray = flatArray.slice(0, 5);
alert(maxArray); // 130,119,108,102,88
I would suggest the following idea:
Since you are looking for the top 5 values, they will, at worst case, all be in the same list. Thus, there are at most 5 * 3 = 15 values to check.
Then, you can take the 5 highest values from each list (which should be trivial if the list is already sorted), and then put them in another list. Now you have a list of the 15, and you want to find the top 5 values from this list. There are different ways to do this - you could sort the list, then take the top 5 values, or you can simply iterate through the list, finding the max each time.
Combine all of the arrays, sort them, then get the last 5 values.
var total = array1.concat(array2, array3);
total = total.sort(function(a,b){return a-b});
//Now total[length-5] is the 5th largest value
//total[length-4] is the 4th largest and so on
Plain Javascript (no libraries added):
var array1=[2,7,12,23,40,44,67,88,102];
var array2=[3,12,14,17,23,40,41,67,108];
var array3=[8,12,23,40,59,86,119,130];
alert(getTopFive(array1, array2, array3));
function getTopFive(ar1, ar2, ar3){
var finalArray = array1.concat(array2).concat(array3);
finalArray.sort(function sortInverse(a,b) { return b - a; });
return finalArray.slice(0, 5);
}