Suppose, if I give 'ABC' as input then then I want 'ABC', 'ACB', 'CAB', 'CBA', 'BAC', 'BCA'. Each word has combination of n! where n is length of letter. I think recursion can make it easier. Here is my code written in javascript :
function reArrange(word)
{
console.log(word);
if (word.length < 0) {
return (-1);
}
else if (word.length == 0) {
return ('');
}
else {
for (var _i = 0; _i < word.length; _i++) {
var temp = word[_i];
for (var _j = 0; _j < word.length; _j++) {
if (_i != _j) {
return word[_i] + reArrange(word.slice(_i, word.length));
}
}
}
}
}
Please use detailed comment.
function combinations(current_string, actual_string, seen) {
var result = [];
if (current_string.length === actual_string.length) {
return [current_string];
}
actual_string.forEach(function(currentChar, index) {
if (seen.indexOf(index) === -1) {
result = [].concat.apply(result, combinations(current_string
+ currentChar, actual_string, seen.concat(index)));
}
});
return result;
}
console.log(combinations("", "ABC".split(""), []));
Output
[ 'ABC', 'ACB', 'BAC', 'BCA', 'CAB', 'CBA' ]
Note: This program works under the assumption that the characters in input string will be unique.
There are three parameters passed to this function. First one is the current string which was built with recursion, second is the array of characters from the actual string, third one is the list of indices already seen in the recursion tree.
The first if condition is the base condition of this recursive solution. If the length of the current string generated is equal to the actual string's length, we have no characters left to process and this is one of the combinations. So, we return that.
If that condition is not met, for each character in actual string, we check if it has been used already (we compare the indices with the indices in the seen). If it is already used in the current recursion, ignore that. Otherwise, concate that with the current string and include this in the seen variable and recurse now.
The result of the recursion will be an array of strings. We need to flatten them (concatenate all the elements of the inner arrays). So, we use [].concat.apply.
Finally, we return the gathered result and here is how the recursion tree looks like
Related
The function has 1 parameter: an array. It should iterate through the array and return strings that contain a number in them. If none of them have an number it will return an empty array.
The code I have written so far seems too verbose. Sometimes it does not return the correct value. I am looking for any ways to shorten the code or improve it.
function numInStr(arr) {
var stringsWithNum = [];
for(var x = 0; x < arr.length - 1; x++) {
for (var y = 0; y < arr[x].length - 1;y++) {
//console.log(typeof arr[x][y]);
if('0123456789'.indexOf(arr[x][y]) !== -1) {
stringsWithNum.push(arr[x]);
break;
}
}
}
return stringsWithNum;
}
You can shorten your code considerably by using .filter() to filter out the elements containing numbers, and using .match() to test whether the elements contain a number.
This eliminates the need to create and maintain (and possibly incorrectly set) array indexes.
function numInStr(arr) {
return arr.filter(function (elmt) {
return elmt.match(/\d/)
})
}
console.log(numInStr(['foo', 'ab12', '34asdf', 'bar']))
// Array [ "ab12", "34asdf" ]
How can I make a search function using regEx?
I have some code but can't post it at the moment due to my computer being very broken and annoying, I will try again tomorrow!
This is not really what would be called combinations, but permutations.
The idea is to use recursion for getting the result for a shorter array, i.e. the one that lacks the first element.
Then take all permutations you get back from the recursive call, and insert the left-out value in each possible index.
When input has duplicates, then you need to stop inserting the left-out value as soon as you find that same value preceding the insertion spot.
Here is how that looks:
function scramble(array) {
if (array.length == 0) {
return [[]];
}
let results = [];
// solve the problem for a shorter array (first value excluded), and iterate:
for (let perm of scramble(array.slice(1))) {
// add the missing element in each possible position:
for (let i = 0; i < array.length; i++) {
// next IF is only needed when input has duplicates, and
// output should not repeat same array:
if (i && array[0] === perm[i-1]) break;
results.push(perm.slice(0, i).concat(array[0], perm.slice(i)));
}
}
return results;
}
let array = ["I", "am", "coding", "am"];
console.log(scramble(array));
Without the inner if, an input with duplicate values will produce duplicate arrays. If this is not desired, then the if is needed.
You could iterate and get a flat array of the mapping of the value with the result of the nested calls.
function permutation(array) {
return array.length === 1
? [array]
: array.flatMap((v, i) => permutation([
...array.slice(0, i),
...array.slice(i + 1)
]).map(a => [v, ...a]));
}
permutation(["I", "am", "coding"]).map(a => console.log(...a));
I have to see if the array given (arr) is in ascending order. (only positive integers given)
I created an array for something to compare it against. Then looped through the input arr to see if each iteration matches. Or at least that was my goal.
Have also tried a counter variable which adds one to the count only every time sorted[i] == arr[i] is true. Then if the count is the same as sorted.length it is true. However, the fact this didn't work made me think I have made a more fundamental error somewhere.
function inAscOrder(arr) {
let sorted = arr.sort((a, b) => a - b);
for (let i = 0; i < arr.length; i++) {
if (arr[i] === sorted[i]) {
return true;
} else {
return false;
}
}
}
sort modifies array in place, so you're comparing two identical arrays. You need to use .slice() on the array first to create a copy.
Also, you need to move return true to the end of the function, otherwise you will return after first match.
function inAscOrder(arr) {
return JSON.stringify(arr) === JSON.stringify(arr.concat().sort()));
}
You don't need to sort your array to check if it's sorted. Loop over each consecutive pair of elements and check if the first is less than the second; if you find a pair for which this isn't true, the array is not sorted.
function inAscOrder(arr) {
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i+1]) {
return false;
}
}
return true;
}
I've written a function that finds all sets of two numbers that sum a target value, given a range of numbers from 0 to x. I'm trying to rewrite it in a way so that you can get a result of a given length n (not only 2), but n numbers that will equal a target when added together.
For example, if the range is 1 to 5 and you want to find all sets of three numbers that add up to 7, the answer would be:
[[1,1,5], [1,2,4], [1,3,3], [2,2,3]]
It looks like the solution is to use a recursive function, but I can't quite figure out how to do this. I've looked at several subset-sum examples on StackOverflow, but none seem to match this particular scenario.
This is not a homework problem. Any help would be appreciated. Here is my findPairs function:
function findPairs(arr, target) {
var pairs = [];
var first = 0;
var last = arr.length-1;
while (first <= last) {
var sum = arr[first] + arr[last];
if (sum === target) {
pairs.push([arr[first], arr[last]]);
first ++;
last--;
}
else if (sum < target) {
first++;
}
else {
last--;
}
}
return pairs;
}
var sample = _.range(11);
console.log(JSON.stringify(findPairs(sample,12)));
// Returns
// [[2,10],[3,9],[4,8],[5,7],[6,6]]
This example uses the lodash _.range function. Fiddle here: https://jsfiddle.net/tbarmann/muoms1vL/10/
You could indeed use recursion. Define the third argument as the length of the sub-arrays you are looking for, and define a recursion function inside that function as follows:
function findSums(arr, target, count) {
var result = [];
function recurse(start, leftOver, selection) {
if (leftOver < 0) return; // failure
if (leftOver === 0 && selection.length == count) {
result.push(selection); // add solution
return;
}
for (var i = start; i < arr.length; i++) {
recurse(i, leftOver-arr[i], selection.concat(arr[i]));
}
}
recurse(0, target, []);
return result;
}
// Demo
var result = findSums([1,2,3,4,5], 7, 3);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Remarks
The solution does not require that the input array has consecutive numbers (range): you might pass it [3,6,4,2,1]. The sub-arrays that are returned will keep the selected elements in order, for example: [3,3,3], [3,4,2] and [6,2,1] could be solutions for targetting 9 with 3 values for that example input.
The numbers must all be non-negative. If negative values are to be allowed, then the optimisation if (leftOver < 0) return; must be removed from the code.
Well, what you are probably looking for is Dynamic Programming. It is an approach where you define mathematically your problem and a recursive solution. Then you try to find a solution, using memoization.
I would make a helper function, where the arguments are (range, target, lengthOfResult). Then do something like:
func helper(arr, target, lengthOfResult){
if(taget == 0) continue;
for(int i=1; i<arr.length-1; i++){
if(taget - arr[i] < 0) return [];
var sub_results = helper(arr, taget - arr[i], lengthOfResult - 1)
foreach(var res in sub_results){
result.concat([arr[i]] + res);
}
}
return result;
}
So you are changing the question for the helper function to "Give me all lists of length-1 which sums up to taget-arr[i]", append to that arr[i]. Then use that to construct the result, for each arr[i].
Basically, every iteration the length will decrease, so the function will terminate at some point. You subtract from the taget whatever number you have now. So you're end result will add up to the desired target.
Note that this algorithm works only with positive numbers. If you can allow negatives, you should remove the if inside the first for-loop.
About the memoization, if you want to allow using each number only once, you could get away with a single array. If you allow reoccurring numbers in the result (like in your example), you probably need a grid; horizontally the target, vertically the lengthOfResult. Then in the beginning of each invocation of the helper method, you check if you already calculated that value. This will save you some recursive calls and make the algorithm not exponential.
function sumPermutations(target, range, number) {
var result = [];
function combo(left, group, sum) {
if(sum > target) return null;
if (left == 0) {
if(sum == target) return group;
return null;
}
for (var i = range.min; i <= range.max; i++) {
var r = combo(left - 1, group.concat(i), sum + i);
if (r)
result.push(r);
}
}
combo(number, [], 0);
return result;
}
console.log(sumPermutations(7, {min: 1, max: 5}, 3));
Note: This gives results with duplicates (all permutaions including those with different orders). You can remove duplicates by sorting the arrays and join thier items and hash them into a hash object.
I'm confused as to why my code is pushing every permutation twice. Please someone help. I'm using heap's algorithm:
var regex = /(.)\1+/g;
function permAlone(str) {
var newArray = str.split('');
var n = newArray.length;
var permutations = [];
var tmp;
function swap(index1, index2) {
tmp = newArray[index1];
newArray[index1] = newArray[index2];
newArray[index2] = tmp;
}
function generate(n, newArray) {
if (n === 1) {
permutations.push(newArray.join(''));
} else {
for(var i = 0; i<n-1; i++) {
generate(n-1, newArray);
swap(n % 2 ? 0 : i, n-1);
permutations.push(newArray.join(''));
}
generate(n-1, newArray);
}
}
generate(n, newArray);
return permutations;
}
permAlone('aab');
The array that is returned is:
["aab", "aab", "aab", "baa", "baa", "aba", "aba", "aba", "baa", "baa"]
So as you can see, the permutations are appearing many more times than intended for each thing. Any help would be great
The code's a little complex and it's difficult to track given the recursion, but if all you want is an array with only unique values, you can simply apply the following code to the result array:
function stripDuplicates(input) {
if (!input || typeof(input) !== 'object' || !('length' in input)) {
throw new Error('input argument is not array.');
}
var newArray = [];
for (var i = 0; i < input.length; i++) {
if (newArray.indexOf(input[i]) === -1) {
newArray.push(input[i]);
}
}
return newArray;
}
This could also be done functionally rather than imperatively, but that's really more of a preference than an optimization issue.
Bálint also points out that you could merely convert the result to a Set, then convert the Set back to an Array, which would automatically strip out any duplicates. Beware, though, that Set is a comparatively new affordance in Javascript and will not function in pre-ES6 environments.
You have a call to:
permutations.push(newArray.join(''));
inside of your for loop. That shouldn't be there. And then, of course if you are permuting strings that have duplicate characters, well, expect to see dupes. e.g., if you permute the string "aa" you'll get two entries from this algorithm "aa" and "aa". Heap's algorithm doesn't try to remove dupes, it treats each element as unique within the string. Obviously, it's trivial to use remove dupes if that's something you care about doing.