How to solve codility minMaxDivision - javascript

I have been trying to wrap my head around this codility question for 1H30,and how to solve with binary search. I found the answer but I cant understand the logic behind it. Can someone who gets it kindly walk me through this answer.
This is the question
Task description
You are given integers K, M and a non-empty zero-indexed array A
consisting of N integers. Every element of the array is not greater
than M.
You should divide this array into K blocks of consecutive elements.
The size of the block is any integer between 0 and N. Every element of
the array should belong to some block.
The sum of the block from X to Y equals A[X] + A[X + 1] + ... + A[Y].
The sum of empty block equals 0.
The large sum is the maximal sum of any block.
For example, you are given integers K = 3, M = 5 and array A such
that:
A[0] = 2 A[1] = 1 A[2] = 5 A[3] = 1 A[4] = 2 A[5] = 2
A[6] = 2
The array can be divided, for example, into the following blocks:
[2, 1, 5, 1, 2, 2, 2], [], [] with a large sum of 15; [2], [1, 5, 1,
2], [2, 2] with a large sum of 9; [2, 1, 5], [], [1, 2, 2, 2] with a
large sum of 8; [2, 1], [5, 1], [2, 2, 2] with a large sum of 6.
The goal is to minimize the large sum. In the above example, 6 is the
minimal large sum.
Write a function:
function solution(K, M, A);
that, given integers K, M and a non-empty zero-indexed array A
consisting of N integers, returns the minimal large sum.
For example, given K = 3, M = 5 and array A such that:
A[0] = 2 A[1] = 1 A[2] = 5 A[3] = 1 A[4] = 2 A[5] = 2
A[6] = 2
the function should return 6, as explained above.
Assume that:
N and K are integers within the range [1..100,000];
M is an integer within the range [0..10,000];
each element of array A is an integer within the range [0..M].
This is the answer I could get my hands on
function solution(K, M, A) {
var begin = A.reduce((a, v) => (a + v), 0)
begin = parseInt((begin+K-1)/K, 10);
var maxA = Math.max(A);
if (maxA > begin) begin = maxA;
var end = begin + M + 1;
var res = 0;
while(begin <= end) {
var mid = (begin + end) / 2;
var sum = 0;
var block = 1;
for (var ind in A) {
var a = A[ind];
sum += a;
if (sum > mid) {
++block;
if (block > K) break;
sum = a;
}
}
if (block > K) {
begin = mid + 1;
} else {
res = mid;
end = mid - 1;
}
}
return res;
}

I would like to give the more detailed explanation of the algorithm that I have implemented and then one correct implementation in C++.
Find the maximum element in the input array. We could also use M, but M does not necessarily occur. A smaller number could be the maximum, so it is slight optimisation.
Calculate the sum of the input array. This would be the maximum largest sum.
Apply binary search, where the start is the maximum element and the end is the sum. The minimum largest sum would be in this range.
For each trial, check whether we can squeeze the elements into fewer blocks than the block number requested. If it is fewer, it is okay because we can use empty blocks. If it is equal, that is also acceptable. However, it is greater, then we can conclude that the tried minimum largest sum needs to be higher to allow individual blocks to be larger to reduce the block count.
One general principle can be observed above that the more fairly we distribute the sums of the blocks, the largest will become the minimum possible. For this, we need to squeeze as many elements into an individual block as possible.
If the number of blocks for a tried minimum largest sum is smaller than the expected block count, then we can try a slightly smaller minimum largest sum, otherwise we have to try a bit greater until we eventually find the best number.
As far as runtime complexity goes, the solution is O(n * log(N * M)) because the binary search is logarithmic. The sum can be N number of times the maximum element M at worst, which results in an N * M range to bisect with binary search. The inner iteration will go through all the elements, so that is N times. Therefore, it is O(N * log(N * M)) which is equivalent to O(N * log(N + M).
int check(vector<int>& A, int largest_sum)
{
int sum = 0;
int count = 0;
for (size_t i = 0; i < A.size(); ++i) {
const int e = A[i];
if ((sum + e) > largest_sum) { sum = 0; ++count; }
sum += e;
}
return count;
}
int solution(int K, int /*M*/, vector<int> &A)
{
int start = *max_element(A.begin(), A.end());
int end = accumulate(A.begin(), A.end(), 0);
while (start <= end) {
int mid = (start + end) / 2;
if (check(A, mid) < K) end = mid - 1;
else start = mid + 1;
}
return start;
}

This is a binary search on the solution. For each candidate solution, we iterate over the whole array once, filling array blocks to the maximum sum the block can be before exceeding the candidate. If the sum is not achievable, there is no point in trying a smaller sum so we search the space of higher possible candidates. And if the sum is achievable, we try the space of lower candidates, while we can.

I have changed a little bit the code so it's more clear, but here is my explanation:
/*
K = numberOfBlocks
M = maxNumber
A = array
*/
function solution(numberOfBlocks, maxNumber, array) {
let begin = array.reduce((a, b) => (a + b), 0); // Calculate total sum of A
begin = Math.ceil(begin / numberOfBlocks); // Calculate the mean of each theorethical block
begin = Math.max(begin, Math.max(...array)); // Set begin to the highest number in array if > than the mean
// In short: begin is now the smallest possible block sum
// Calculate largest possible block sum
let end = begin + maxNumber + 1;
var result = 0;
while (begin <= end) {
// Calculate the midpoint, which is our result guess
const midpoint = (begin + end) / 2;
let currentBlockSum = 0;
let block = 1;
for (let number of array) {
currentBlockSum += number;
// If currentBlockSum > midpoint means that we are
// in a different block...
if (currentBlockSum > midpoint) {
++block;
// ...so we reset sum with the current number
currentBlockSum = number;
// but if we are out of blocks, our guess (midpoint) is incorrect
// and we will have to adjust it
if (block > numberOfBlocks)
break;
}
}
// If we are out of blocks
// it means that our guess (midpoint) is bigger than we thought
if (block > numberOfBlocks) {
begin = midpoint + 1;
// else, it's smaller
} else {
result = midpoint;
end = midpoint - 1;
}
}
return result;
}

Looking and testing at the solutions, none of them actually work.
I decided to spend some time on it, here is my solution (working for any use case with maximum performance).
using System;
using System.Linq;
class Solution
{
public int solution(int K, int M, int[] A)
{
int start = Math.Max((int)Math.Ceiling((decimal)A.Sum()/(decimal)K), A.Max());
int end = A.Sum();
int result = 0;
while(start <= end)
{
int dicotomie = (end + start) / 2;
if(calculateNbBlocks(dicotomie, A) <= K)
{
result = dicotomie;
end = dicotomie - 1;
}
else
start = dicotomie + 1;
}
return result;
}
public int calculateNbBlocks(int dicotomie, int[] A)
{
int nbBlocks = 1;
int sum = 0;
for(int i=0; i<A.Length; i++)
{
sum += A[i];
if(sum > dicotomie)
{
sum = A[i];
nbBlocks++;
}
}
return nbBlocks;
}
}

Scored 100% on Codility (https://app.codility.com/demo/results/trainingQYJ68K-KJR/) using const midpoint = Math.floor((begin + end) / 2);
instead of
const midpoint = (begin + end) / 2;
after copying Javascript code in answer by pytness (Nov 5, 2020 at 8:40).
/*
K = numberOfBlocks
M = maxNumber
A = array
*/
function solution(numberOfBlocks, maxNumber, array) {
let begin = array.reduce((a, b) => (a + b), 0); // Calculate total sum of A
// console.log("total sum of A: ", begin);
begin = Math.ceil(begin / numberOfBlocks); // Calculate the mean of each theoretical block
// console.log('Math.ceil(begin / numberOfBlocks): ', begin);
begin = Math.max(begin, Math.max(...array)); // Set begin to the highest number in array if > than the mean
// console.log('Math.max(begin, Math.max(...array)): ', begin);
// In short: begin is now the smallest possible block sum
// Calculate largest possible block sum
let end = begin + maxNumber + 1;
// console.log("end: ", end);
var result = 0;
while (begin <= end) {
// Calculate the midpoint, which is our result guess
const midpoint = Math.floor((begin + end) / 2);
// console.log("midpoint: ", midpoint);
let currentBlockSum = 0;
let block = 1;
for (let number of array) {
currentBlockSum += number;
// console.log("currentBlockSum: ", currentBlockSum);
// If currentBlockSum > midpoint means that we are
// in a different block...
if (currentBlockSum > midpoint) {
// console.log("currentBlockSum > midpoint");
++block;
// console.log("block: ", block);
// ...so we reset sum with the current number
currentBlockSum = number;
// console.log("currentBlockSum: ", currentBlockSum);
// but if we are out of blocks, our guess (midpoint) is incorrect
// and we will have to adjust it
if (block > numberOfBlocks) {
// console.log("block > numberOfBlocks before break");
// console.log("block: ", block);
// console.log("break");
break;
}
}
}
// If we are out of blocks, it means that our guess for midpoint is too small.
if (block > numberOfBlocks) {
// console.log("block > numberOfBlocks before begin");
begin = midpoint + 1;
// console.log("begin: ", begin);
}
// Else, it's too big.
else {
// console.log("block <= numberOfBlocks");
result = midpoint;
// console.log("result: ", result);
end = midpoint - 1;
// console.log("end: ", end);
}
}
// console.log("result: ", result);
return result;
}

Related

that returns the sum of all numbers between two chosen numbers

I'm totally stuck at one excersise question. Can someone help me out with this question?
Create a function sumRangeNumbers() that returns the sum of all numbers
between two chosen numbers. The function should take two arguments, one
representing the lowest boundary and one that represents the highest
boundary. For example, the arguments 10 and 20 should return the sum of
10+11+12+13...+20.
for (var i = 0; i < 82; i++) {
document.write(i + i + '+');
}
How do I write the loop that sums all the numbers with an function?
The answer of DCR already provides a nice implementation and is probably what you were looking for. However, with a little mathematical knowledge you can make the function a little easier.
We know that the sum of 1 to n is n(n+1)/2 by looking at this wikipedia page.
The sum of a to b, is simply the sum of 1 to b minus the sum of 1 to a - 1 (we also want to include a itself).
The sum between a and b is then b(b + 1)/2 - (a - 1)(a)/2 and therefore your function becomes:
const a = 10
const b = 20
function sumRangeNumbers(a, b) {
const high = Math.max(a, b);
const low = Math.min(a, b);
return high * (high + 1) / 2 - (low - 1) * (low) / 2;
}
console.log(sumRangeNumbers(a, b)); // 165
console.log(sumRangeNumbers(b, a)); // 165
console.log(sumRangeNumbers(5, 7)); // 18
function sumRangeNumber (num1, num2) {
let total = 0
for (let i = num1; i <= num2; i++) {
total += i
}
return total
}
You are on the right track with a for loop. What we did here was in place of declaring i as zero we passed the low value and in the comparison we pass the high value. This creates the range ie 10-20. From there each loop we add I too total which is declared outside fo the loop so as to not have it reset and we add to it.
As a previous comment mentioned, this is kinda doing your HW for you, so give the above function a shot and play around with it and change things to make sure you understand whats happening.
you need to first create a function and then you need to call it.
function sum(x,y){
var sum = 0;
for(let i = x;i<=y;i++){
sum = sum + i;
}
console.log(sum)
}
sum(1,10);
const sumRange = (num1, num2) => (
min = Math.min(num1, num2),
Array(Math.abs(num1 - num2) + 1)
.fill().map((_, i) => i + min)
.reduce((sum, el) => sum + el, 0)
);
console.log(sumRange(20, 10));
console.log(sumRange(10, 20));
function sumRangeNumbers(lower, upper) {
let total = 0;
for (let index=lower; index<=upper; index++) {
total = total + index;
}
return total;
}
document.write(sumRangeNumbers(10,20));
Simple:
function sumRangeNumbers(from, to) {
let result = 0;
for (let i = from; i <= to; i++) {
result += i;
}
return result;
}
If the numbers belong to range of natural numbers, then why do you need a loop. Just use the fact that sum from low to high=
((high-low+1) * (low + high)) / 2
Give this a shot:
function getSum(x,y) {
sum += x
console.log(sum, x)
if (x == y) { return sum }
else { return getSum(x+1,y) }
}
sum = 0
Here's a simple example using your current attempt. Keep in mind, you'll want to some error handling for cases where they give you an invalid high/low number.
IE:
if (lowNum >= highNum) { console.error('invalid range'); }
and maybe this too
if (typeof lowNum !== 'number' && typeof highNum !== 'number') { console.error('Invalid inputs'); }
function sumUp(lowNum, highNum) {
if (lowNum >= highNum) { throw new Error('Invalid Range'); }
// Initialize total at 0
let total = 0;
// Loop through numbers between lowNum and highNum.
// Do not include lowNum and highNum in the addition
for (let i = lowNum + 1; i < highNum; i++) {
// Increment the total with the 'in-between number (i)'
total += i;
}
// Return the result
return total;
}
// Test 1 (should be 44)
console.log(2 + 3 + 4 + 5 + 6 + 7 + 8 + 9, sumUp(1, 10));
// Test 2 (should be 315)
console.log(50 + 51 + 52 + 53 + 54 + 55, sumUp(49, 56));
// If you really want to do document.write
document.write(sumUp(49, 56));
// Test 3 (should fail)
console.log(sumUp(15, 3));

Make array consecutive

i got stucked in a chalenge in codeFights.my code pass the simple test and fail in just 2 from five of hidden tests her is the chalenge instruction:
Ratiorg got statues of different sizes as a present from CodeMaster for his birthday, each statue having an non-negative integer size. Since he likes to make things perfect, he wants to arrange them from smallest to largest so that each statue will be bigger than the previous one exactly by 1. He may need some additional statues to be able to accomplish that. Help him figure out the minimum number of additional statues needed.
Example
For statues = [6, 2, 3, 8], the output should be
makeArrayConsecutive2(statues) = 3.
Ratiorg needs statues of sizes 4, 5 and 7.
Input/Output
[time limit] 4000ms (js)
[input] array.integer statues
An array of distinct non-negative integers.
Constraints:
1 ≤ statues.length ≤ 10,
0 ≤ statues[i] ≤ 20.
[output] integer
The minimal number of statues that need to be added to existing statues such that it contains every integer size from an interval [L, R] (for some L, R) and no other sizes.
and here is my code :
function makeArrayConsecutive2(statues) {
//range the table from min to max
var rang=statues.sort();
var some=0;
//if the table is one element
if(rang.length-1==0){
return 0;
}else{
//if the table contain more then one element
for(i=0;i<=rang.length-2;i++){
//add the deference of two consecutive position -1
//to find the number of missing numbers
some+=(rang[i+1]-rang[i]-1);
}
return some;
}
}
Everything is correct, except the sorting part.
You have used sort function to sort the array in increasing order
var rang = statues.sort();
But if sort function is not provided a compare function, it converts its elements in strings and then sort it in unicode order.
For eg: [2,1,11] will be sorted as [1,11,2] which will give undesired output.
Correct way is
var rang = statues.sort(function (a, b){
return (a - b)
});
SO THE LOGIC TO SOLVE THIS QUESTION IS:
Find the Smallest and Largest Element in Array.
Get the count of can say, difference of Largest and Smallest value of array in order to calculate, how many elements must be there to make it as a continuous array
. Like from 5 to 9, count of total elements must be 5 ( i.e.5,6,7,8,9) and also add 1 to the result to make count inclusive.
Find the Length of the Array
Subtract the count i.e. "difference of largest and smallest value " with the length of array
PYTHON CODE (For explanation):
def makeArrayConsecutive2(statues):
max_height = max(statues)
min_height = min(statues)
array_length = len(statues)
count_of_element = max_height - min_height + 1
# '1 ' is added to make it inclusive
return count_of_element-array_length
and Python one liner :
def makeArrayConsecutive2(statues):
return max(statues)-min(statues)-len(statues)+1
I agree with Deepak's Solution. The question is ready not about sorting but helping to figure out the minimum number of additional statues needed. You only need to get the max and min values.
int makeArrayConsecutive2(int[] statues)
{
int min=Integer.MAX_VALUE,max=-1;
for(int i=0;i<statues.length;i++)
{
if(statues[i] < min){ min = statues[i]; }
if(statues[i] > max){ max = statues[i]; }
}
return (max-min)+1 - statues.length;
}
Solution in typescript. Create a new array from the min and max from the status array using a for loop. Subtract new array length with status array length.
function makeArrayConsecutive2(statues: number[]): number {
let min = Math.min(...statues);
let max = Math.max(...statues);
let arr = [];
for (let i = min; i <= max; i++) {
arr.push(i);
}
return arr.length - statues.length;
}
function makeArrayConsecutive2(statues) {
const nums = [];
for (let i = Math.min(...statues); i <= Math.max(...statues); i++) {
if (!statues.includes(i)) {
nums.push(i);
}
}
return nums.length;
}
console.log(makeArrayConsecutive2([6, 2, 3, 8]))
Sorting (nlogn)is not required. Below is the solution in Java.
int makeArrayConsecutive2(int[] statues) {
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int i = 0; i < statues.length; i++) {
max = Math.max(max, statues[i]);
min = Math.min(min, statues[i]);
}
return (max - min) + 1 - statues.length;
}
This Code works
var statues = [2, 3, 6, 8];
var newStatues = [];
Function declaration
function makeArrayConsecutive2(statues) {
statues.sort(function(a, b) { return a - b });
for(var i = statues[0]; i <= statues[statues.length-1]; i++) {
newStatues.push(i);
}
return console.log(newStatues.length - statues.length);
}
Function Calling
makeArrayConsecutive2(statues);
Best solution goes here in just O(1) complexity:
let n = statues.length;
let max = Math.max.apply(null, statues);
let min = Math.min.apply(null, statues);
return max - min - n + 1;
function makeArrayConsecutive2(statues) {
var rang = statues.sort(function (a, b){
return (a - b)
});
var some=0;
if(rang.length-1==0){
return 0;
}else{
for(i=0;i<=rang.length-2;i++){
some+=(rang[i+1]-rang[i]-1);
}
return some;
}
}
function makeArrayConsecutive2(statues) {
const n = statues.length;
const min = Math.min(...statues);
const max = Math.max(...statues);
return max - min - n + 1;
}
If we subtract the minimum from the maximum element, then we get the number of elements that should be in the final array. Now subtract the already existing number of elements from this amount and add 1, then we get the result we need - the number of missing elements
Just for fun in C#
static int makeArrayConsecutive2(int[] statues)
{
List<int> ConsecutiveNums = new List<int>();
for(int i = statues.Min(); i != statues.Max() + 1; i++)
ConsecutiveNums.Add(i);
return ConsecutiveNums.Count - statues.Length;
}
function makeArrayConsecutive2(statues) {
return Math.max(...statues) - Math.min(...statues) + 1 -(statues.length)
}
I don't think we need a Looping there, that's my solution
you can try using for loop and ternary operation by the following code
def makeArrayConsecutive2(statues):
count=0
for i in range (min(statues),max(statues)):
count=count+1 if i not in statues else count
return count
function makeArrayConsecutive2(statues) {
s = statues.sort(function(a, b){return a - b});
n = statues.length;
val = 0;
for (let i=0;i<n-1;i++) {
val += (Math.abs(s[i]-s[i+1]))-1;
}
return val;
}
sort(statues.begin(), statues.end());
int count = 0;
for(int i = 1;i<statues.size(); i++){
int diff = statues[i]-statues[i-1];
if(diff>1){
count+=diff-1;
}
}
return count;
Solution in PHP
function solution($statues) {
return max($statues) - min($statues) - count($statues) + 1;
}
PHP solution for question.
function solution($statues) {
sort($statues);
$missing = 0;
$lowest = min($statues);
$highest = max($statues);
$numbers = range($lowest, $highest);
foreach($numbers as $number){
if(!in_array($number, $statues)){
$missing++;
}
}
return $missing;
}
here is code in python
def solution(statues):
statues.sort()
c = 0
for i in range(len(statues)-1):
if statues[i+1]-statues[i] > 1:
c += statues[i+1]-statues[i] -1
return (c)

How to return an array of values, the sums of which equal a specified number

I'm trying to create an array of numbers of a set length, defining the minimum and a maximum number in the set, and letting a function determine the rest of the numbers between. The kicker is that the sum of this array of numbers must be equal to a predetermined value. The trick is figuring out how that function works.
I found this on stack overflow, which got me the following function:
export const distributeValues = (amount, weights=[]) => {
const distributedAmounts = []
let totalWeights = weights.reduce( (a,b) => a + b)
weights.forEach( weight => {
const weightValue = parseFloat(weight)
const percentage = weightValue / totalWeights
const distributedAmount = Math.round(percentage * amount)
distributedAmounts.push(distributedAmount)
totalWeights -= weightValue
amount -= distributedAmount
})
return distributedAmounts
}
This seems like a good start, but I actually need to work backwards; I'm trying to figure out a function that will give me the weights that would be passed into the above function.
Right now, I have this, a function broken into two parts (apologies for the redundancy):
export const getDistributions = (amount, distributions, modifier) => {
const values = []
let amountLeft = amount;
for (let i = 0; i < distributions; i++ ) {
const value = Math.max(Math.round((amountLeft / (modifier || 4))),1)
amountLeft -= value
values.push(value)
}
// -------------------------------------------- //
// --- correct for cases where total values --- //
// --- end up greater/less than amount --- //
// -------------------------------------------- //
let iterator = 0
let totalAssignedValue = values.reduce((a,b) => a+b);
const lastIndex = (values.length - 1);
const getIndex = (iterator, values) => {
return iterator > lastIndex ? iterator % lastIndex : iterator
}
while (totalAssignedValue > amount) {
iterator = getIndex(iterator)
if (iterator !== lastIndex && iterator !== 0 && values[iterator] > 1) {
values[iterator]--
}
iterator ++
totalAssignedValue = values.reduce((a,b) => a+b);
}
while (totalAssignedValue < amount) {
iterator = getIndex(iterator)
if (iterator !== lastIndex && iterator !== 0) {
values[iterator]++
}
iterator ++
totalAssignedValue = values.reduce((a,b) => a+b);
}
// -------------------------------------------- //
// -------------- end correction -------------- //
// -------------------------------------------- //
return values;
}
The first part tries and distributes the values, but invariably I end up with values that are greater or lesser than the input amount, so there's a second part of the equation that fixes that. Seems a little unclean though, and it's a little arbitrary how the remainders get distributed, so a pure mathematical solution would be great.
I'm starting to wonder if I'm going to need calculus for this, because I basically have the integral (the sum of the array's values), the range of the integral (min and max values), and now have to figure out the formula for the curve. This may be overkill at this point, though.
Thanks for the input!
How about this? First create the set in such way that the first member is the minimum, the second member is minimum + 1, the third minimum + 2, etc. Then sum up the numbers in the set and subtract the sum from the predetermined value. Then distribute the result of the subtraction among all the numbers in the set as outlined betlow.
Set makeSet(int preDet, int min, int max, int setLength)
{
if((max + max - setLength + 1) * setLength / 2 < preDet) return null;
if((min + min + setLength - 1) * setLength / 2 > preDet) return null;
Set set = Set(setLength);
int val = min;
for (int i = 0; i < setLength; i++)
{
set[i] = val++;
}
int sum = (min + val - 1) * setLength / 2;
int dev = preDet - sum;
if(dev)
{
int adj = dev / setLength;
if(dev % setLength) adj++;
for(int i = setLength -1; dev; i--)
{
if(adj > dev) adj = dev;
set[i] += adj;
dev -= adj;
}
}
return set;
}

Permutations without recursive function call

Requirement: Algorithm to generate all possible combinations of a set , without duplicates , or recursively calling function to return results.
The majority , if not all of the Answers provided at Permutations in JavaScript? recursively call a function from within a loop or other function to return results.
Example of recursive function call within loop
function p(a, b, res) {
var b = b || [], res = res || [], len = a.length;
if (!len)
res.push(b)
else
for (var i = 0; i < len
// recursive call to `p` here
; p(a.slice(0, i).concat(a.slice(i + 1, len)), b.concat(a[i]), res)
, i++
);
return res
}
p(["a", "b", "c"]);
The current Question attempts to create the given permutation in a linear process , relying on the previous permutation.
For example , given an array
var arr = ["a", "b", "c"];
to determine the total number of possible permutations
for (var len = 1, i = k = arr.length; len < i ; k *= len++);
k should return 6 , or total number of possible permutations of arr ["a", "b", "c"]
With the total number of individual permutations determined for a set , the resulting array which would contain all six permutations could be created and filled using Array.prototype.slice() , Array.prototype.concat() and Array.prototype.reverse()
var res = new Array(new Array(k));
res[0] = arr;
res[1] = res[0].slice(0,1).concat(res[0].slice(-2).reverse());
res[2] = res[1].slice(-1).concat(res[1].slice(0,2));
res[3] = res[2].slice(0,1).concat(res[2].slice(-2).reverse());
res[4] = res[3].slice(-2).concat(res[3].slice(0,1));
res[5] = res[4].slice(0,1).concat(res[4].slice(-2).reverse());
Attempted to reproduce results based on the pattern displayed at the graph for An Ordered Lexicographic Permutation Algorithm based on one published in Practical Algorithms in C++ at Calculating Permutations and Job Interview Questions .
There appears to be a pattern that could be extended if the input set was , for example
["a", "b", "c", "d", "e"]
where 120 permutations would be expected.
An example of an attempt at filling array relying only on previous permutation
// returns duplicate entries at `j`
var arr = ["a", "b", "c", "d", "e"], j = [];
var i = k = arr.length;
arr.forEach(function(a, b, array) {
if (b > 1) {
k *= b;
if (b === i -1) {
for (var q = 0;j.length < k;q++) {
if (q === 0) {
j[q] = array;
} else {
j[q] = !(q % i)
? array.slice(q % i).reverse().concat(array.slice(0, q % i))
: array.slice(q % i).concat(array.slice(0, q % i));
}
}
}
}
})
however have not yet been able to make the necessary adjustments at parameters for .slice() , .concat() , .reverse() at above js to step from one permutation to the next ; while only using the previous array entry within res to determine current permutation , without using recursive.
Noticed even , odd balance of calls and tried to use modulus % operator and input array .length to either call .reverse() or not at ["a", "b", "c", "d", "e"] array , though did not produce results without duplicate entries.
The expected result is that the above pattern could be reduced to two lines called in succession for the duration of the process until all permutations completed, res filled ; one each for call to .reverse() , call without .reverse() ; e.g., after res[0] filled
// odd , how to adjust `.slice()` , `.concat()` parameters
// for array of unknown `n` `.length` ?
res[i] = res[i - 1].slice(0,1).concat(res[i - 1].slice(-2).reverse());
// even
res[i] = res[1 - 1].slice(-1).concat(res[i - 1].slice(0,2));
Question: What adjustments to above pattern are necessary , in particular parameters , or index , passed .slice() , .concat() to produce all possible permutations of a given set without using a recursive call to the currently processing function ?
var arr = ["a", "b", "c"];
for (var len = 1, i = k = arr.length; len < i; k *= len++);
var res = new Array(new Array(k));
res[0] = arr;
res[1] = res[0].slice(0, 1).concat(res[0].slice(-2).reverse());
res[2] = res[1].slice(-1).concat(res[1].slice(0, 2));
res[3] = res[2].slice(0, 1).concat(res[2].slice(-2).reverse());
res[4] = res[3].slice(-2).concat(res[3].slice(0, 1));
res[5] = res[4].slice(0, 1).concat(res[4].slice(-2).reverse());
console.log(res);
Edit, Update
Have found a process to utilize pattern described above to return permutations in lexicographic order for an input up to .length 4 , using a single for loop. Expected results are not returned for array with .length of 5.
The pattern is based on the second chart at "Calculating Permutations and Job Interview Questions"[0].
Would prefer not to use .splice() or .sort() to return results, though used here while attempting to adhere to last "rotate" requirement at each column. The variable r should reference the index of the first element of the next permutation, which it does.
The use of .splice() , .sort() could be included if their usage followed the pattern at the chart ; though at js below, they actually do not.
Not entirely certain that the issue with js below is only the statement following if (i % (total / len) === reset) , though that portion required the most investment of time; yet still does not return expected results.
Specifically, now referring to the chart, at rotating , for example 2 to index 0, 1 to index 2. Attempted to achieve this by using r , which is a negative index, to traverses from right to left to retrieve next item that should be positioned at index 0 of adjacent "column".
At next column, 2 would be placed at index 2 , 3 would be placed at index 0. This is portion, as far as have been able to grasp or debug, so far, is the area where error is occurring.
Again, returns expected results for [1,2,3,4], though not for [1,2,3,4,5]
var arr = [1, 2, 3, 4];
for (var l = 1, j = total = arr.length; l < j ; total *= l++);
for (var i = 1
, reset = 0
, idx = 0
, r = 0
, len = arr.length
, res = [arr]
; i < total; i++) {
// previous permutation
var prev = res[i - 1];
// if we are at permutation `6` here, or, completion of all
// permutations beginning with `1`;
// setting next "column", place `2` at `index` 0;
// following all permutations beginning with `2`, place `3` at
// `index` `0`; with same process for `3` to `4`
if (i % (total / len) === reset) {
r = --r % -(len);
var next = prev.slice(r);
if (r === -1) {
// first implementation used for setting item at index `-1`
// to `index` 0
// would prefer to use single process for all "rotations",
// instead of splitting into `if` , `else`, though not there, yet
res[i] = [next[0]].concat(prev.slice(0, 1), prev.slice(1, len - 1)
.reverse());
} else {
// workaround for "rotation" at from `index` `r` to `index` `0`
// the chart does not actually use the previous permutation here,
// but rather, the first permutation of that particular "column";
// here, using `r` `,i`, `len`, would be
// `res[i - (i - 1) % (total / len)]`
var curr = prev.slice();
// this may be useful, to retrieve `r`,
// `prev` without item at `r` `index`
curr.splice(prev.indexOf(next[0]), 1);
// this is not optiomal
curr.sort(function(a, b) {
return arr.indexOf(a) > arr.indexOf(b)
});
// place `next[0]` at `index` `0`
// place remainder of sorted array at `index` `1` - n
curr.splice(0, 0, next[0])
res[i] = curr
}
idx = reset;
} else {
if (i % 2) {
// odd
res[i] = prev.slice(0, len - 2).concat(prev.slice(-2)
.reverse())
} else {
// even
--idx
res[i] = prev.slice(0, len - (len - 1))
.concat(prev.slice(idx), prev.slice(1, len + (idx)))
}
}
}
// try with `arr` : `[1,2,3,4,5]` to return `res` that is not correct;
// how can above `js` be adjusted to return correct results for `[1,2,3,4,5]` ?
console.log(res, res.length)
Resources:
Generating Permutation with Javascript
(Countdown) QuickPerm Head Lexicography:
(Formally Example_03 ~ Palindromes)
Generating all Permutations [non-recursive]
(Attempt to port to from C++ to javascript jsfiddle http://jsfiddle.net/tvvvjf3p/)
Calculating Permutation without Recursion - Part 2
permutations of a string using iteration
iterative-permutation
Permutations by swapping
Evaluation of permutation algorithms
Permutation algorithm without recursion? Java
Non-recursive algorithm for full permutation with repetitive elements?
String permutations in Java (non-recursive)
Generating permutations lazily
How to generate all permutations of a list in Python
Can all permutations of a set or string be generated in O(n log n) time?
Finding the nth lexicographic permutation of ‘0123456789’
Combinations and Permutations
Here is a simple solution to compute the nth permutation of a string:
function string_nth_permutation(str, n) {
var len = str.length, i, f, res;
for (f = i = 1; i <= len; i++)
f *= i;
if (n >= 0 && n < f) {
for (res = ""; len > 0; len--) {
f /= len;
i = Math.floor(n / f);
n %= f;
res += str.charAt(i);
str = str.substring(0, i) + str.substring(i + 1);
}
}
return res;
}
The algorithm follows these simple steps:
first compute f = len!, there are factorial(len) total permutations of a set of len different elements.
as the first element, divide the permutation number by (len-1)! and chose the element at the resulting offset. There are (len-1)! different permutations that have any given element as their first element.
remove the chosen element from the set and use the remainder of the division as the permutation number to keep going.
perform these steps with the rest of the set, whose length is reduced by one.
This algorithm is very simple and has interesting properties:
It computes the n-th permutation directly.
If the set is ordered, the permutations are generated in lexicographical order.
It works even if set elements cannot be compared to one another, such as objects, arrays, functions...
Permutation number 0 is the set in the order given.
Permutation number factorial(a.length)-1 is the last one: the set a in reverse order.
Permutations outside this range are returned as undefined.
It can easily be converted to handle a set stored as an array:
function array_nth_permutation(a, n) {
var b = a.slice(); // copy of the set
var len = a.length; // length of the set
var res; // return value, undefined
var i, f;
// compute f = factorial(len)
for (f = i = 1; i <= len; i++)
f *= i;
// if the permutation number is within range
if (n >= 0 && n < f) {
// start with the empty set, loop for len elements
for (res = []; len > 0; len--) {
// determine the next element:
// there are f/len subsets for each possible element,
f /= len;
// a simple division gives the leading element index
i = Math.floor(n / f);
// alternately: i = (n - n % f) / f;
res.push(b.splice(i, 1)[0]);
// reduce n for the remaining subset:
// compute the remainder of the above division
n %= f;
// extract the i-th element from b and push it at the end of res
}
}
// return the permutated set or undefined if n is out of range
return res;
}
clarification:
f is first computed as factorial(len).
For each step, f is divided by len, giving exacty the previous factorial.
n divided by this new value of f gives the slot number among the len slots that have the same initial element. Javascript does not have integral division, we could use (n / f) ... 0) to convert the result of the division to its integral part but it introduces a limitation to sets of 12 elements. Math.floor(n / f) allows for sets of up to 18 elements. We could also use (n - n % f) / f, probably more efficient too.
n must be reduced to the permutation number within this slot, that is the remainder of the division n / f.
We could use i differently in the second loop, storing the division remainder, avoiding Math.floor() and the extra % operator. Here is an alternative for this loop that may be even less readable:
// start with the empty set, loop for len elements
for (res = []; len > 0; len--) {
i = n % (f /= len);
res.push(b.splice((n - i) / f, 1)[0]);
n = i;
}
I think this post should help you. The algorithm should be easily translatable to JavaScript (I think it is more than 70% already JavaScript-compatible).
slice and reverse are bad calls to use if you are after efficiency. The algorithm described in the post is following the most efficient implementation of the next_permutation function, that is even integrated in some programming languages (like C++ e.g.)
EDIT
As I iterated over the algorithm once again I think you can just remove the types of the variables and you should be good to go in JavaScript.
EDIT
JavaScript version:
function nextPermutation(array) {
// Find non-increasing suffix
var i = array.length - 1;
while (i > 0 && array[i - 1] >= array[i])
i--;
if (i <= 0)
return false;
// Find successor to pivot
var j = array.length - 1;
while (array[j] <= array[i - 1])
j--;
var temp = array[i - 1];
array[i - 1] = array[j];
array[j] = temp;
// Reverse suffix
j = array.length - 1;
while (i < j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
return true;
}
One method to create permutations is by adding each element in all of the spaces between elements in all of the results so far. This can be done without recursion using loops and a queue.
JavaScript code:
function ps(a){
var res = [[]];
for (var i=0; i<a.length; i++){
while(res[res.length-1].length == i){
var l = res.pop();
for (var j=0; j<=l.length; j++){
var copy = l.slice();
copy.splice(j,0,a[i]);
res.unshift(copy);
}
}
}
return res;
}
console.log(JSON.stringify(ps(['a','b','c','d'])));
Here could be another solution, inspired from the Steinhaus-Johnson-Trotter algorithm:
function p(input) {
var i, j, k, temp, base, current, outputs = [[input[0]]];
for (i = 1; i < input.length; i++) {
current = [];
for (j = 0; j < outputs.length; j++) {
base = outputs[j];
for (k = 0; k <= base.length; k++) {
temp = base.slice();
temp.splice(k, 0, input[i]);
current.push(temp);
}
}
outputs = current;
}
return outputs;
}
// call
var outputs = p(["a", "b", "c", "d"]);
for (var i = 0; i < outputs.length; i++) {
document.write(JSON.stringify(outputs[i]) + "<br />");
}
Here's a snippet for an approach that I came up with on my own, but naturally was also able to find it described elsewhere:
generatePermutations = function(arr) {
if (arr.length < 2) {
return arr.slice();
}
var factorial = [1];
for (var i = 1; i <= arr.length; i++) {
factorial.push(factorial[factorial.length - 1] * i);
}
var allPerms = [];
for (var permNumber = 0; permNumber < factorial[factorial.length - 1]; permNumber++) {
var unused = arr.slice();
var nextPerm = [];
while (unused.length) {
var nextIndex = Math.floor((permNumber % factorial[unused.length]) / factorial[unused.length - 1]);
nextPerm.push(unused[nextIndex]);
unused.splice(nextIndex, 1);
}
allPerms.push(nextPerm);
}
return allPerms;
};
Enter comma-separated string (e.g. a,b,c):
<br/>
<input id="arrInput" type="text" />
<br/>
<button onclick="perms.innerHTML = generatePermutations(arrInput.value.split(',')).join('<br/>')">
Generate permutations
</button>
<br/>
<div id="perms"></div>
Explanation
Since there are factorial(arr.length) permutations for a given array arr, each number between 0 and factorial(arr.length)-1 encodes a particular permutation. To unencode a permutation number, repeatedly remove elements from arr until there are no elements left. The exact index of which element to remove is given by the formula (permNumber % factorial(arr.length)) / factorial(arr.length-1). Other formulas could be used to determine the index to remove, as long as it preserves the one-to-one mapping between number and permutation.
Example
The following is how all permutations would be generated for the array (a,b,c,d):
# Perm 1st El 2nd El 3rd El 4th El
0 abcd (a,b,c,d)[0] (b,c,d)[0] (c,d)[0] (d)[0]
1 abdc (a,b,c,d)[0] (b,c,d)[0] (c,d)[1] (c)[0]
2 acbd (a,b,c,d)[0] (b,c,d)[1] (b,d)[0] (d)[0]
3 acdb (a,b,c,d)[0] (b,c,d)[1] (b,d)[1] (b)[0]
4 adbc (a,b,c,d)[0] (b,c,d)[2] (b,c)[0] (c)[0]
5 adcb (a,b,c,d)[0] (b,c,d)[2] (b,c)[1] (b)[0]
6 bacd (a,b,c,d)[1] (a,c,d)[0] (c,d)[0] (d)[0]
7 badc (a,b,c,d)[1] (a,c,d)[0] (c,d)[1] (c)[0]
8 bcad (a,b,c,d)[1] (a,c,d)[1] (a,d)[0] (d)[0]
9 bcda (a,b,c,d)[1] (a,c,d)[1] (a,d)[1] (a)[0]
10 bdac (a,b,c,d)[1] (a,c,d)[2] (a,c)[0] (c)[0]
11 bdca (a,b,c,d)[1] (a,c,d)[2] (a,c)[1] (a)[0]
12 cabd (a,b,c,d)[2] (a,b,d)[0] (b,d)[0] (d)[0]
13 cadb (a,b,c,d)[2] (a,b,d)[0] (b,d)[1] (b)[0]
14 cbad (a,b,c,d)[2] (a,b,d)[1] (a,d)[0] (d)[0]
15 cbda (a,b,c,d)[2] (a,b,d)[1] (a,d)[1] (a)[0]
16 cdab (a,b,c,d)[2] (a,b,d)[2] (a,b)[0] (b)[0]
17 cdba (a,b,c,d)[2] (a,b,d)[2] (a,b)[1] (a)[0]
18 dabc (a,b,c,d)[3] (a,b,c)[0] (b,c)[0] (c)[0]
19 dacb (a,b,c,d)[3] (a,b,c)[0] (b,c)[1] (b)[0]
20 dbac (a,b,c,d)[3] (a,b,c)[1] (a,c)[0] (c)[0]
21 dbca (a,b,c,d)[3] (a,b,c)[1] (a,c)[1] (a)[0]
22 dcab (a,b,c,d)[3] (a,b,c)[2] (a,b)[0] (b)[0]
23 dcba (a,b,c,d)[3] (a,b,c)[2] (a,b)[1] (a)[0]
Note that each permutation # is of the form:
(firstElIndex * 3!) + (secondElIndex * 2!) + (thirdElIndex * 1!) + (fourthElIndex * 0!)
which is basically the reverse process of the formula given in the explanation.
I dare to add another answer, aiming at answering you question regarding slice, concat, reverse.
The answer is it is possible (almost), but it would not be quite effective. What you are doing in your algorithm is the following:
Find the first inversion in the permutation array, right-to-left (inversion in this case defined as i and j where i < j and perm[i] > perm[j], indices given left-to-right)
place the bigger number of the inversion
concatenate the processed numbers in reversed order, which will be the same as sorted order, as no inversions were observed.
concatenate the second number of the inversion (still sorted in accordsnce with the previos number, as no inversions were observed)
This is mainly, what my first answer does, but in a bit more optimal manner.
Example
Consider the permutation 9,10, 11, 8, 7, 6, 5, 4 ,3,2,1
The first inversion right-to-left is 10, 11.
And really the next permutation is:
9,11,1,2,3,4,5,6,7,8,9,10=9concat(11)concat(rev(8,7,6,5,4,3,2,1))concat(10)
Source code
Here I include the source code as I envision it:
var nextPermutation = function(arr) {
for (var i = arr.length - 2; i >= 0; i--) {
if (arr[i] < arr[i + 1]) {
return arr.slice(0, i).concat([arr[i + 1]]).concat(arr.slice(i + 2).reverse()).concat([arr[i]]);
}
}
// return again the first permutation if calling next permutation on last.
return arr.reverse();
}
console.log(nextPermutation([9, 10, 11, 8, 7, 6, 5, 4, 3, 2, 1]));
console.log(nextPermutation([6, 5, 4, 3, 2, 1]));
console.log(nextPermutation([1, 2, 3, 4, 5, 6]));
The code is avaiable for jsfiddle here.
A fairly simple C++ code without recursion.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <string>
// Integer data
void print_all_permutations(std::vector<int> &data) {
std::stable_sort(std::begin(data), std::end(data));
do {
std::copy(data.begin(), data.end(), std::ostream_iterator<int>(std::cout, " ")), std::cout << '\n';
} while (std::next_permutation(std::begin(data), std::end(data)));
}
// Character data (string)
void print_all_permutations(std::string &data) {
std::stable_sort(std::begin(data), std::end(data));
do {
std::copy(data.begin(), data.end(), std::ostream_iterator<char>(std::cout, " ")), std::cout << '\n';
} while (std::next_permutation(std::begin(data), std::end(data)));
}
int main()
{
std::vector<int> v({1,2,3,4});
print_all_permutations(v);
std::string s("abcd");
print_all_permutations(s);
return 0;
}
We can find next permutation of a sequence in linear time.
Here is an answer from #le_m. It might be of help.
The following very efficient algorithm uses Heap's method to generate all permutations of N elements with runtime complexity in O(N!):
function permute(permutation) {
var length = permutation.length,
result = [permutation.slice()],
c = new Array(length).fill(0),
i = 1, k, p;
while (i < length) {
if (c[i] < i) {
k = i % 2 && c[i];
p = permutation[i];
permutation[i] = permutation[k];
permutation[k] = p;
++c[i];
i = 1;
result.push(permutation.slice());
} else {
c[i] = 0;
++i;
}
}
return result;
}
console.log(JSON.stringify(permute([1, 2, 3, 4])));
You can use a stack to go through permutations.
This approach is ideal when dealing with trees or other problems while not leaning on recursion.
You will need to make adjustments to not have any duplicate values.
type permutation = [string, string[]]
function p(str: string): string[]{
const res: string[] = []
const stack: permutation[] = [["", str.split('')]]
while(stack.length){
const [head, tail] = stack.pop()
if(!tail.length){
res.push(head)
continue
}
for(let i = 0; i < tail.length; i++){
let newTail = tail.slice()
newTail.splice(i, 1)
stack.push([head + tail[i], newTail])
}
}
return res
}

Summation\ Addition of two arrays (particular)

"A positive number of whatever length is represented as an array of numerical characters, ergo between '0's and '9's. We know that the most significant cypher is in position of index 0 of the array.
Example:
- Number is 10282
- Array will be number = [1,0,2,8,2]
This considered, create a function of 2 arrays representing two positive numbers that calculates the SUM\ADDITION\SUMMATION of both of them and set it in a third array, containing the sum of the first 2."
This is how the exercise is translated from my own language, italian.
This is my solution but it doesnt entirely work. I have tried with basic stuff like
A=[1,4] and B=[4,7]. The results should be C=[6,1] but it gives me [5,1] as it considers the line where I use the modular but not the one where I say that the -1 index position should take a ++.
Help <3
alert('Insert A length');
var k=asknum();
alert('Insert B length');
var h=asknum();
var A = new Array(k);
var B = new Array(h);
// asknum() is only defined in this particular environment we are
// using at the university. I guess the turnaround would be -prompt-
function readVet(vet){//inserts values in index positions
for(i=0;i<vet.length;i++)
vet[i]=asknum();
}
readVet(A);//fills array
readVet(B);//fills array
function sumArray(vet1,vet2){
var C = new Array();
for(i=vet1.length-1;i>(-1);i--){
for(n=vet2.length-1;n>(-1);n--){
C[i]=vet1[i]+vet2[i];
if(C[i]>9){
C[i]=C[i]%10;
C[i-1]=C[i-1]++;
}
}
}
return C;
}
print(sumArray(A,B));
I'm not sure what you're doing with a nested for loop here. You just need one. Also, to make said loop really simple, normalize the arrays first so that both are the length of the larger array + 1 element (in case of carry). Then correct the result on the way out of the function.
function normalizeArray(array, digits) {
var zeroCnt = digits - array.length,
zeroes = [];
while (zeroCnt--) {
zeroes.push(0);
}
return zeroes.concat(array);
}
function sumArrays(a1, a2) {
var maxResultLength = Math.max(a1.length, a2.length) + 1;
a1 = normalizeArray(a1, maxResultLength);
a2 = normalizeArray(a2, maxResultLength);
var result = normalizeArray([], maxResultLength);
var i = maxResultLength - 1, // working index
digit = 0, // working result digit
c = 0; // carry (0 or 1)
while (i >= 0) {
digit = a1[i] + a2[i] + c;
if (digit > 9) {
c = 1;
digit -= 10;
} else {
c = 0;
}
result[i--] = digit;
}
/* If there was no carry into the most significant digit, chop off the extra 0 */
/* If the caller gave us arrays with a bunch of leading zeroes, chop those off */
/* but don't be an idiot and slice for every digit like sqykly =D */
for (i = 0 ; i < result.length && result[i] === 0 ; i++) {
/* result = result.slice(1); don't do that, or anything */
}
return result.slice(i);
}
That gives the expected output.
I may be missing something because the other answers look much more complicated, but here's my attempt at providing an answer based on the question:
// Takes an array and generates the sum of the elements
function addArrayNumbers(arr) {
return arr.reduce(function (p, c) {
return String(p) + String(c);
});
}
// Sums two numbers and returns an array based on that sum
function addCombinedNumbers(a, b) {
return String(Number(a) + Number(b)).split('');
}
var arrone = [1, 4];
var arrtwo = [4, 7];
var one = addArrayNumbers(arrone);
var two = addArrayNumbers(arrtwo);
var c = addCombinedNumbers(one, two); // [6,1]
Fiddle
I followed a different approach that may very well be less efficient than yours, but i consider it to be much clearer. One important thing is that i reverse the arrays so the least significant bit is first. Comments are in the code.
function sum(a,b){
// ensure a is the largest of the two arrays
if (a.length < b.length)
return sum(b,a);
// flip the arrays so the least significant digit is first
a = a.reverse();
b = b.reverse();
// c will hold the result (reversed at first)
var c = [];
// add each number individually
var carry = a.reduce(function(carry,digitA,index){
// digitA is guaranteed to be a number, digit from b is not!
var sum = digitA + (b[index] || 0) + carry;
c.push(sum%10);
return Math.floor(sum/10); // this is carried to the next step of the addition
},0); // initial carry is 0
if (carry) c.push(1); // resolve if carry exists after all digits have been added
return c.reverse();
}
// Usage:
console.log(sum([1,0,8,3],[1,3,5])); // [1, 2, 1, 8]
console.log(sum([8,3],[7,9])); // [1, 6, 2]
PS: There are many problems with your code. For one, you cannot use two nested loops:
var a = [0,1];
var b = [2,3];
for (var i=0; i<a.length; i++) {
for (var j=0; j<b.length; j++) {
console.log(a[i] + ' ' + b[i]);
}
}
// will output: 0 2, 0 3, 1 2, 1 3
// you want something along the lines of: 0 2, 1 3
What you want is a single loop that iterates over both arrays simultaneously.
My attempt at an efficient solution:
function efficientSum(a,b){
var i = a.length, j = b.length;
if (i<j) return efficientSum(j,i);
var q = 0, c = [];
c.length = i;
while (i) {
c[--i] = a[i] + (b[--j] || 0) + q;
q = c[i] > 9 ? ((c[i]-=10),1) : 0; // comma operator, ugly!
}
if (q) c.unshift(1);
return c;
}

Categories