Related
I want to generate an addition equation for a random number which is look likes
5+10+2 from a set of numbers i.e [1,2,5,10,50].
var randomNumber = Math.floor(Math.random() * (10 - 1 + 1)) + 1;
var setOfNums = [1,2,5,10,50];
var additionEquation; //ex: for randomNumber = 28; additionEquation = 10+10+5+2+1;
And the maximum number of elements in equation is 5.Is it possible in java script?Thanks in advance.
You may have multiple solutions. A dynamical programming approach could efficiently solve this;
function getCombos(a,t){
var h = {},
len = a.length,
n = 0;
for (var i = 0; i < len; i++){
n = a[i];
h[n] ? h[n].push([n]) : h[n] = [[n]];
for(var j = a[0]; j <= t-n; j++){
h[j] && (h[j+n] = h[j+n] ? h[j+n].concat(h[j].map(s => s.concat(n)))
: h[j].map(s => s.concat(n)));
}
}
return h[t] || [];
}
var arr = [1,2,5,10,50],
target = 28,
result = [];
console.time("combos");
result = getCombos(arr,target);
console.timeEnd("combos");
console.log(`${result.length} solutions found`);
console.log(JSON.stringify(result));
Then you may choose the shortest one among the results set. However calculating according to a maxlen will of couse save us from calculating excess results just to be filtered out later. So the following code only works up until the maxlen is achieved.
function getCombos(a,t,l){
var h = {},
len = a.length,
n = 0;
for (var i = 0; i < len; i++){
n = a[i];
h[n] ? h[n].push([n]) : h[n] = [[n]];
for(var j = a[0]; j <= t-n; j++){
h[j] && (h[j+n] = h[j+n] ? h[j+n].concat(h[j].reduce((r,s) => s.length < l ? (r.push(s.concat(n)),r) : r, []))
: h[j].reduce((r,s) => s.length < l ? (r.push(s.concat(n)),r) : r, []));
}
}
return h[t] || [];
}
var arr = [1,2,5,10,50],
target = 28,
maxlen = 5,
result = [];
console.time("combos");
result = getCombos(arr,target,maxlen);
console.timeEnd("combos");
console.log(result.length)
console.log(JSON.stringify(result));
I believe performance wise this can not be beaten easily. It takes only .190ms to get to the result [[1,2,5,10,10]].
This problem can be solved with a recursive combinations of all possible sums until we reach the target.
One solution contains maximum 5 as a length where 5 is the length of the setOfNums array.
var randomNumber = Math.floor(Math.random() * 30) + 1;
console.log(randomNumber);
var setOfNums = [1,2,5,10,50];
setOfNums=setOfNums.sort(function(a,b){
return b-a;
});
subset_sum(setOfNums,randomNumber);
function subset_sum(numbers, target, partial){
partial = partial || [];
s = partial.reduce(function(contor,elem){
return contor+elem;
},0);
if(s == target){
partial=partial.sort(function(a,b){
return a-b;
});
console.log("sum"+JSON.stringify(partial)+"="+ target);
}
if(s >= target)
return;
if(partial.length>numbers.length)
return;
numbers.forEach(function(number,index){
n = numbers[index];
subset_sum(numbers, target, partial.concat(n));
});
}
Disclaimer: I know part of this question has been asked and answered here before and yes, they have helped me get to this point so far.
Let's say I have an array that contains 2 elements and I want to find ALL possible combinations that could be made up of these elements. The order of the sets does not matter.
var myArr = ['a','b'];
Desired result
var result = [ [a], [a,b], [b], [b,a] ]
At first I thought I was looking for a power set however I do not want a null set and I want to treat [a,b] and [b,a] as unique sequences NOT as equals. More info about sets, null set, and equal sets here.
So far I have written this function that will recursively loop through my array, create new arrays for each possible combinations and push them into a results array.
function getCombinations() {
var myArr = ['a','b'],
result = [];
var recurFn = function(prefix, myArr) {
for (var i = 0; i < myArr.length; i++) {
var newArray = prefix !== '' ? [prefix, myArr[i]] : [myArr[i]];
result.push(newArray);
recurFn(prefix + myArr[i], myArr.slice(i + 1));
}
}
recurFn('', myArr);
console.log(result); //[[a], [a,b], [b]]
}
Here is a fiddle with my above code.
Currently I am only returning 3 possible combinations [a], [a,b], [b], how can I edit my code so that I am returning [a], [a,b], [b], [b,a].
Thanks!
Can you make two arrays in reverse order:
var myArr = ['a','b']
var myArr2 = ['b','a']
var recurFn = function(prefix, myArr) {
for (var i = 0; i < myArr.length; i++) {
var newArray = prefix !== '' ? [prefix, myArr[i]] : [myArr[i]];
result.push(newArray);
recurFn(prefix + myArr[i], myArr.slice(i + 1));
}
for (var i = 0; i < myArr2.length; i++) {
var newArray2 = prefix !== '' ? [prefix, myArr2[i]] : [myArr2[i]];
result.push(newArray2);
recurFn(prefix + myArr2[i], myArr2.slice(i + 1));
}
newArray.concat(newArray2);
newArray.unique();
}
Try this, works for all array sizes:
jsfiddle: https://jsfiddle.net/fcwa3cz5/2/
console.log(allArrCombi(['a','b','c']));
function allArrCombi(arr){
var hash={};
var res=[];
arr.sort();
var len=Math.pow(2, arr.length);
for (var i=1;i<len;i++){
var lineRes=[];
for (var innerPos=0;innerPos < arr.length;innerPos++){
var mask = 1 << innerPos;
if (mask & i){
lineRes.push(arr[innerPos]);
}
}
do{
if (!hash[arr.join("-")]){ // did we have this combinatin already
res.push(lineRes.slice())
}
}while(nextPermutation(lineRes))
}
return res;
}
function nextPermutation(array) {
var i = array.length - 1;
while (i > 0 && array[i - 1] >= array[i])
i--;
if (i <= 0)
return false;
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;
j = array.length - 1;
while (i < j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
return true;
}
I am trying to count the number of permutations that do not contain consecutive letters. My code passes tests like 'aabb' (answer:8) and 'aab' (answer:2), but does not pass cases like 'abcdefa'(my answer: 2520; correct answer: 3600). Here's my code:
function permAlone(str) {
var totalPerm = 1;
var result = [];
//assign the first letter
for (var i = 0; i < str.length; i++) {
var firstNum = str[i];
var perm = firstNum;
//create an array from the remaining letters in the string
for (var k = 0; k < str.length; k++) {
if (k !== i) {
perm += str[k];
}
}
//Permutations: get the last letter and change its position by -1;
//Keep changing that letters's position by -1 until its index is 1;
//Then, take the last letter again and do the same thing;
//Keep doing the same thing until the total num of permutations of the number of items in the string -1 is reached (factorial of the number of items in the string -1 because we already established what the very first letter must be).
var permArr = perm.split("");
var j = permArr.length - 1;
var patternsLeft = totalNumPatterns(perm.length - 1);
while (patternsLeft > 0) {
var to = j - 1;
var subRes = permArr.move(j, to);
console.log(subRes);
if (noDoubleLettersPresent(subRes)) {
result.push([subRes]);
}
j -= 1;
if (j == 1) {
j = perm.length - 1;
}
patternsLeft--;
}
}
return result.length;
}
Array.prototype.move = function(from, to) {
this.splice(to, 0, (this.splice(from, 1))[0]);
return this.join("");
};
function totalNumPatterns(numOfRotatingItems) {
var iter = 1;
for (var q = numOfRotatingItems; q > 1; q--) {
iter *= q;
}
return iter;
}
function noDoubleLettersPresent(str) {
if (str.match(/(.)\1/g)) {
return false;
} else {
return true;
}
}
permAlone('abcdefa');
I think the problem was your permutation algorithm; where did you get that from? I tried it with a different one (after Filip Nguyen, adapted from his answer to this question) and it returns 3600 as expected.
function permAlone(str) {
var result = 0;
var fact = [1];
for (var i = 1; i <= str.length; i++) {
fact[i] = i * fact[i - 1];
}
for (var i = 0; i < fact[str.length]; i++) {
var perm = "";
var temp = str;
var code = i;
for (var pos = str.length; pos > 0; pos--) {
var sel = code / fact[pos - 1];
perm += temp.charAt(sel);
code = code % fact[pos - 1];
temp = temp.substring(0, sel) + temp.substring(sel + 1);
}
console.log(perm);
if (! perm.match(/(.)\1/g)) result++;
}
return result;
}
alert(permAlone('abcdefa'));
UPDATE: In response to a related question, I wrote an algorithm which doesn't just brute force all the permutations and then skips the ones with adjacent doubles, but uses a logical way to only generate the correct permutations. It's explained here: Permutations excluding repeated characters and expanded to include any number of repeats per character here: Generate all permutations of a list without adjacent equal elements
I agree with m69, the bug seems to be in how you are generating permutations. I got 3600 for 'abcdefa' by implementing a different algorithm for generating permutations. My solution is below. Since it uses recursion to generate the permutations the solution is not fast, however you may find the code easier to follow, if speed is not important.
The reason for having a separate function to generate the array index values in the permutations was to verify that the permutation code was working properly. Since there are duplicate values in the input strings it's harder to debug issues in the permutation algorithm.
// Simple helper function to compute all permutations of string indices
function permute_indices_helper(input) {
var result = [];
if (input.length == 0) {
return [[]];
}
for(var i = 0; i < input.length; i++) {
var head = input.splice(i, 1)[0];
var tails = permute_indices_helper(input);
for (var j = 0; j < tails.length; j++) {
tails[j].splice(0, 0, head);
result.push(tails[j]);
}
input.splice(i, 0, head); // check
}
return result;
};
// Given an array length, generate all permutations of possible indices
// for array of that length.
// Example: permute_indices(2) generates:
// [[0,1,2], [0,2,1], [1,0,2], ... , [2, 0, 1]]
function permute_indices(array_length) {
var result = [];
for (var i = 0; i < array_length; i++) {
result.push(i);
}
return permute_indices_helper(result);
}
// Rearrange letters of input string according to indices.
// Example: "car", [2, 1, 0]
// returns: "rac"
function rearrange_string(str, indices) {
var result = "";
for (var i = 0; i < indices.length; i++) {
var string_index = indices[i];
result += str[string_index];
}
return result;
}
function permAlone(str) {
var result = 0;
var permutation_indices = permute_indices(str.length);
for (var i = 0; i < permutation_indices.length; i++) {
var permuted_string = rearrange_string(str, permutation_indices[i]);
if (! permuted_string.match(/(.)\1/g)) result++;
}
return result;
}
You can see a working example on JSFiddle.
To shuffle a string, I could use something like this
String.prototype.shuffle = function () {
var arr = this.split("");
var len = arr.length;
for (var n = len - 1; n > 0; n--) {
m = Math.floor(Math.random() * (n + 1));
tmp = arr[n];
arr[n] = arr[m];
arr[m] = tmp;
}
return arr.join("");
}
But how could I randomly space it with n characters, while preserving the string order?
For example:
"test" => "t-es--t"
"test" => "-t-e-st"
"test" => "te--st-"
I've thought about creating a list from the string, generating a random number to represent an index, and then shifting the list to the left, but is there a better way to do this?
This will insert n characters char randomly into the string. If char is missing, it defaults to a space:
String.prototype.shuffle = function(n, char) {
var arr = this.split(''),
char= char || ' ';
while(n--) {
arr.splice(Math.floor(Math.random() * (arr.length+1)), 0, char);
}
return arr.join('');
} //shuffle
This Fiddle shows the relative random distribution using the method.
If you want a truly unbiased solution that produces all possibilities equally likely, and have access to a perfect random number generator (which is a whole other topic), there's a fairly easy solution. Let's define some terms:
m = number of characters in the string
k = number of spaces you want to insert (you called this n)
Consider one solution to this problem with m=7 and k=3:
0123456789
cab ba g e
What the problem essentially amounts to is choosing k different numbers from among a set of m+k numbers. There are (m+k)!/(m!*k!) possibilities. This is the concept of combinations and is similar to the stars-and-bars problem in the Wikipedia page. (To get an unbiased generator you would need a random number generator with the number of state values much higher than this number of possibilities. But I said RNGs are a whole other topic.)
Here's an example in Python showing all possibilities:
import itertools
def show_all(s, k):
# show all combinations of k spaces inserted into string s
m = len(s)
for sample in itertools.combinations(range(m+k),k):
jprev = 0
out = ''
for ispace, i in enumerate(sample):
j = i-ispace # adjust index by number of spaces used
out += s[jprev:j] + ' '
jprev = j
out += s[jprev:]
yield sample, out
for sample, out in show_all('shoe',2):
print sample,':'+out+':'
output:
(0, 1) : shoe:
(0, 2) : s hoe:
(0, 3) : sh oe:
(0, 4) : sho e:
(0, 5) : shoe :
(1, 2) :s hoe:
(1, 3) :s h oe:
(1, 4) :s ho e:
(1, 5) :s hoe :
(2, 3) :sh oe:
(2, 4) :sh o e:
(2, 5) :sh oe :
(3, 4) :sho e:
(3, 5) :sho e :
(4, 5) :shoe :
Now the problem becomes one of generating a random combination. In Python this is part of the itertools recipes:
def random_combination_with_replacement(iterable, r):
"Random selection from itertools.combinations_with_replacement(iterable, r)"
pool = tuple(iterable)
n = len(pool)
indices = sorted(random.randrange(n) for i in xrange(r))
return tuple(pool[i] for i in indices))
In Javascript we have to implement this ourselves, which we can do using Robert Floyd's algorithm for sampling without replacement:
pseudocode:
initialize set S to empty
for J := N-M + 1 to N do
T := RandInt(1, J)
if T is not in S then
insert T in S
else
insert J in S
Javascript:
function random_comb(r, n, m)
{
/* Generate a combination of m distinct random integers between 0 and n-1
using Floyd's algorithm
r: random generation function
such that r(k) generates an integer in the range [0, k-1]
*/
var S = {};
var out = [];
for (var i = 0; i < m; ++i)
{
var j = i+(n-m);
var t = r(j+1);
var item = (t in S) ? j : t;
S[item] = 1;
out.push(item);
}
return out.sort();
}
Now let's put it all together, ignoring the fact that Math.random() is inadequate:
var r = function(n) { return Math.floor(Math.random()*n); }
function random_comb(r, n, m)
{
/* Generate a combination of m distinct random integers between 0 and n-1
using Floyd's algorithm
r: random generation function
such that r(k) generates an integer in the range [0, k-1]
*/
var S = {};
var out = [];
for (var i = 0; i < m; ++i)
{
var j = i+(n-m);
var t = r(j+1);
var item = (t in S) ? j : t;
S[item] = 1;
out.push(item);
}
return out.sort();
}
function random_insert(r, s, k, c)
{
/* randomly insert k instances of character c into string s */
var m = s.length;
var S = random_comb(r, m+k, k);
var jprev = 0;
var out = '';
for (var ispace = 0; ispace < k; ++ispace)
{
var i = S[ispace];
var j = i - ispace; // adjust index by # of spaces
out += s.slice(jprev,j) + c;
jprev = j;
}
out += s.slice(jprev);
return out;
}
var word = 'shoe';
var results = [];
for (var i = 0; i < 10; ++i)
{
results.push(random_insert(r,word, 2, '-'));
}
var tally = {};
for (var i = 0; i < 100000; ++i)
{
var s = random_insert(r,word,2,'-');
tally[s] = (s in tally) ? (tally[s] + 1) : 1;
}
for (var s in tally)
{
results.push(s+": "+tally[s]);
}
for (var i = 0; i < results.length; ++i)
{
$("#results").append(results[i]+'<br>');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="results"></div>
Working jsFiddle
Even though I loved #Barmar 's idea..
You can do it by simply looping and randomizing positions to insert the spaces..
String.prototype.insertSpaces = function (n, char) {
var str = this;
for(var i = 0; i < n; i++){
var randPos = Math.floor(Math.random() * (str.length + 1)); // get random index to insert
str = str.substring(0, randPos) + char + str.substring(randPos, str.legnth); // insert the repeated sting
}
return str;
}
function addRandomSpaces(str,n,char){
for (var newstr="", i=0; i<str.length;){
if (n && Math.random()<0.5) {
newstr += char;
n--;
} else {
newstr += str[i++];
}
}
while(n--){
newstr += char;
}
return newstr;
}
Here's a function that will loop through a given string str, adding n instances of char at random places. If when it finishes, n items haven't been added, it adds finishes them at the end.
You can use the slice function insert the new character:
var x = "this is phrase";
var y = " a";
[x.slice(0,7), y, x.slice(7)].join('');
Result: this is a phrase
Something like this:
String.prototype.shuffle2 = function() {
'use strict';
var numberOfSpaces = Math.floor(Math.random() * (this.length - 1));
var word = this;
for (var i = 0; i < numberOfSpaces; i++) {
var index = Math.floor(Math.random() * (this.length - 1));
word = [word.slice(0,index), '-', word.slice(index)].join('');
}
return word;
};
Greetings!
String.prototype.addspace = function () {
var arr = this.split("");
var len = arr.length;
maxSp = 4;
for(var i = 0; i <= len; i++){
m = Math.floor(Math.random() * (maxSp + 1));
for(var j = 0; j < m ; j++){
arr.splice(i,0," ");
}
len += m;
i +=m;
}
return arr.join("");
}
alert("Juanito".addspace().shuffle());
What is a fast and simple implementation of interleave:
console.log( interleave([1,2,3,4,5,6] ,2) ); // [1,4,2,5,3,6]
console.log( interleave([1,2,3,4,5,6,7,8] ,2) ); // [1,5,2,6,3,7,4,8]
console.log( interleave([1,2,3,4,5,6] ,3) ); // [1,3,5,2,4,6]
console.log( interleave([1,2,3,4,5,6,7,8,9],3) ); // [1,4,7,2,5,8,3,6,9]
This mimics taking the array and splitting it into n equal parts, and then shifting items off the front of each partial array in sequence. (n=2 simulates a perfect halving and single shuffle of a deck of cards.)
I don't much care exactly what happens when the number of items in the array is not evenly divisible by n. Reasonable answers might either interleave the leftovers, or even "punt" and throw them all onto the end.
function interleave( deck, step ) {
var copyDeck = deck.slice(),
stop = Math.floor(copyDeck.length/step),
newDeck = [];
for (var i=0; i<step; i++) {
for (var j=0; j<stop; j++) {
newDeck[i + (j*step)] = copyDeck.shift();
}
}
if(copyDeck.length>0) {
newDeck = newDeck.concat(copyDeck);
}
return newDeck;
}
It could be done with a counter instead of shift()
function interleave( deck, step ) {
var len = deck.length,
stop = Math.floor(len/step),
newDeck = [],
cnt=0;
for (var i=0; i<step; i++) {
for (var j=0; j<stop; j++) {
newDeck[i + (j*step)] = deck[cnt++];
}
}
if(cnt<len) {
newDeck = newDeck.concat(deck.slice(cnt,len));
}
return newDeck;
}
And instead of appending the extras to the end, we can use ceil and exit when we run out
function interleave( deck, step ) {
var copyDeck = deck.slice(),
stop = Math.ceil(copyDeck.length/step),
newDeck = [];
for (var i=0; i<step; i++) {
for (var j=0; j<stop && copyDeck.length>0; j++) {
newDeck[i + (j*step)] = copyDeck.shift();
}
}
return newDeck;
}
can i has prize? :-D
function interleave(a, n) {
var i, d = a.length + 1, r = [];
for (i = 0; i < a.length; i++) {
r[i] = a[Math.floor(i * d / n % a.length)];
}
return r;
}
according to my tests r.push(... is faster than r[i] = ... so do with that as you like..
note this only works consistently with sets perfectly divisible by n, here is the most optimized version i can come up with:
function interleave(a, n) {
var i, d = (a.length + 1) / n, r = [a[0]];
for (i = 1; i < a.length; i++) {
r.push(a[Math.floor(i * d) % a.length]);
}
return r;
}
O(n-1), can anyone come up with a log version? to the mathmobile! [spinning mathman logo]
Without for loops (I've added some checkup for the equal blocks):
function interleave(arr, blocks)
{
var len = arr.length / blocks, ret = [], i = 0;
if (len % 1 != 0) return false;
while(arr.length>0)
{
ret.push(arr.splice(i, 1)[0]);
i += (len-1);
if (i>arr.length-1) {i = 0; len--;}
}
return ret;
}
alert(interleave([1,2,3,4,5,6,7,8], 2));
And playground :) http://jsfiddle.net/7tC9F/
how about functional with recursion:
function interleave(a, n) {
function f(a1, d) {
var next = a1.length && f(a1.slice(d), d);
a1.length = Math.min(a1.length, d);
return function(a2) {
if (!a1.length) {
return false;
}
a2.push(a1.shift());
if (next) {
next(a2);
}
return true;
};
}
var r = [], x = f(a, Math.ceil(a.length / n));
while (x(r)) {}
return r;
}
Phrogz was pretty close, but it didn't interleave properly. This is based on that effort:
function interleave(items, parts) {
var len = items.length;
var step = len/parts | 0;
var result = [];
for (var i=0, j; i<step; ++i) {
j = i
while (j < len) {
result.push(items[j]);
j += step;
}
}
return result;
}
interleave([0,1,2,3], 2); // 0,2,1,3
interleave([0,1,2,3,4,5,6,7,8,9,10,11], 2) // 0,6,1,7,2,8,3,9,4,10,5,11
interleave([0,1,2,3,4,5,6,7,8,9,10,11], 3) // 0,4,8,1,5,9,2,6,10,3,7,11
interleave([0,1,2,3,4,5,6,7,8,9,10,11], 4) // 0,3,6,9,1,4,7,10,2,5,8,11
interleave([0,1,2,3,4,5,6,7,8,9,10,11], 5) // 0,2,4,6,8,10,1,3,5,7,9,11
Since I've been pushed to add my own answer early (edited to fix bugs noted by RobG):
function interleave(items,parts){
var stride = Math.ceil( items.length / parts ) || 1;
var result = [], len=items.length;
for (var i=0;i<stride;++i){
for (var j=i;j<len;j+=stride){
result.push(items[j]);
}
}
return result;
}
try this one:
function interleave(deck, base){
var subdecks = [];
for(count = 0; count < base; count++){
subdecks[count] = [];
}
for(var count = 0, subdeck = 0; count < deck.length; count++){
subdecks[subdeck].push(deck[count]);
subdeck = subdeck == base - 1? 0 : subdeck + 1;
}
var newDeck = [];
for(count = 0; count < base; count++){
newDeck = newDeck.concat(subdecks[count]);
}
return newDeck;
}