Permutation: Push function not working, JavaScript O(n*n!) runtime - javascript

The problem at hand is :
Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.
I have this code with an ok run time but it seems that the push function is not working, I am not sure why bc it all makes sense in general
Example 1:
Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Constraints:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
All the integers of nums are unique.
var permute = function(nums) {
if (nums == null) {
return []
}
return getPermutations(nums);
};
function getPermutations(arr) {
var set = {}
var size = factorial(arr.length)
var result = []
while (Object.keys(set).length < size) {
for (var i = 0; i < arr.length && result.length < size; i++) {
for (var j = arr.length - 1; j >= 0 && result.length < size; j--) {
if (!set[arr]) {
set[arr] = 1
console.log(arr) //clearly see the permutations printed
result.push(arr) //why is this not working...
}
arr = swap(arr,i,j)
}
}
}
return result
}
function swap(arr,i,j) {
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
return arr
}
function factorial(n) {
if (n == 0 || n == 1) {
return 1
}
return n*factorial(n-1)
}

You're pushing the same array multiple times into the result array.
You can fix this by creating a copy of the arr array before pushing it.
(So the code after it can't mutate the array again)
So instead of result.push(arr) you could use one of those examples:
// using splash operator
result.push([...arr]);
// Array#slice()
result.push(arr.slice());
// Array.from()
result.push(Array.from(arr));
// etc...
Working Example:
var permute = function(nums) {
if (nums == null) {
return []
}
return getPermutations(nums);
};
function getPermutations(arr) {
var set = {}
var size = factorial(arr.length)
var result = []
while (Object.keys(set).length < size) {
for (var i = 0; i < arr.length && result.length < size; i++) {
for (var j = arr.length - 1; j >= 0 && result.length < size; j--) {
if (!set[arr]) {
set[arr] = 1
console.log(arr) //clearly see the permutations printed
result.push([...arr]) //why is this not working...
}
arr = swap(arr,i,j)
}
}
}
return result
}
function swap(arr,i,j) {
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
return arr
}
function factorial(n) {
if (n == 0 || n == 1) {
return 1
}
return n*factorial(n-1)
}
console.log(permute([1,2,3]));
This question could also be a good read, it contains a lot of examples for how to efficiently calculate permutations in javascript.

Related

Return 0 if there are no string in an array - JS

I have a function here that takes the smallest number in an array.
What I did is that I filtered out only numbers using typeof property and compared the values from Infinity.
Right now, it will return 0 if the array is empty.
However if the array contains only string or other datatypes it will return Infinity.
Here's my codes:
function findSmallestNumberAmongMixedElements(arr) {
var smallestNum = Infinity;
if(arr.length !== 0){
for(var i = 0; i < arr.length; i++){
if(typeof arr[i] === 'number' && arr[i] < smallestNum){
smallestNum = arr[i];
}
}
return smallestNum;
}
return 0;
}
var output = findSmallestNumberAmongMixedElements(['sam', 3, 2, 1]);
console.log(output); // --> 4
It must return 0 as well if there are no numbers in the array.
Any idea what am I doing wrong here?
There are probably some more elegant ways to solve this. but this fixes your bug.
function findSmallestNumberAmongMixedElements(arr) {
var smallestNum = Infinity;
var numberFound = false
for(var i = 0; i < arr.length; i++){
if(typeof arr[i] === 'number' && arr[i] < smallestNum){
smallestNum = arr[i];
numberFound = true
}
}
if(numberFound)
return smallestNum;
return 0;
}
The problem is that you are special-casing the empty-array case, with the line
if(arr.length !== 0){
Remove that. Then, if you want to force a result of Infinity to 0, do that at the end.
function findSmallestNumberAmongMixedElements(arr) {
var smallestNum = Infinity;
for(var i = 0; i < arr.length; i++){
if(typeof arr[i] === 'number' && arr[i] < smallestNum){
smallestNum = arr[i];
}
}
return isFinite(smallestNum) ? smallestNum : 0;
}
However, it is simpler to just filter out the non-numbers using filter, and calculate the minimum using Math.min. This also makes easier to fix a "bug" in the code above, which is that it will yield 0 for inputs such as [Infinity, "foo", Infinity]. I'm not sure whether you prefer to return 0 or Infinity in that kind of case. Assuming you do want to return 0, then
function findSmallestNumberAmongMixedElements(arr) {
var nums = ...arr.filter(elt => typeof elt === 'number');
return nums.length ? Math.min(...nums) : 0;
}
function findSmallestNumberAmongMixedElements(arr) {
var smallestNum = Infinity;
if(arr.length !== 0){
for(var i = 0; i < arr.length; i++){
if(typeof arr[i] === 'number' && arr[i] < smallestNum){
smallestNum = arr[i];
}
}
return smallestNum == Infinity? 0 : smallestNum; // if smallest doesn't change return 0
}
return 0;
}
var output = findSmallestNumberAmongMixedElements(['sam', 3, 2, 1]);
console.log(output);
You could use an odd way of using Array#reduce and Array#filter
First, filter out non-numeric
Second reduce this filtered array, with an initial value of 0 - if the array is zero length, reduce will return 0
function findSmallestNumberAmongMixedElements(arr) {
var smallestNum = Infinity;
return arr.filter(item => typeof item == 'number').reduce((min,item) => {
if(item < smallestNum) smallestNum = item;
return smallestNum;
}, 0);
}
console.log(findSmallestNumberAmongMixedElements([]));
console.log(findSmallestNumberAmongMixedElements(['1','2','3']));
console.log(findSmallestNumberAmongMixedElements([1,2,3]));
console.log(findSmallestNumberAmongMixedElements(['1',2,3]));

Finding first duplicate in an array and returning the minimal index

So the question reads:
Given an array a that contains only numbers in the range from 1 to a.length, find the first duplicate number for which the second occurrence has the minimal index. In other words, if there are more than 1 duplicated numbers, return the number for which the second occurrence has a smaller index than the second occurrence of the other number does. If there are no such elements, return -1.
Write a solution with O(n) time complexity and O(1) additional space complexity.
I have a solution, but apparently it's not fast enough and stalls when there are over a thousand items in the array.
This is what I have:
function firstDuplicate(arr) {
let dictionary = {};
for(let i = 0, ii = arr.length; i < ii; i++) {
for(let z = i+1, zz = arr.length; z < zz; z++) {
if(arr[i] === arr[z]) {
if(dictionary.hasOwnProperty(arr[i])) {
if(dictionary[arr[i]] !== 0 && dictionary[arr[i]] > z) {
dictionary[i] = z;
}
} else {
dictionary[arr[i]] = z;
}
}
}
}
let answer = [];
for(key in dictionary) {
// [array number, position];
answer.push([key, dictionary[key]]);
};
if(answer.length > 0) {
return Number(answer.sort((a, b) => {
return a[1]-b[1];
})[0][0]);
}
return -1;
}
I think converting the object into an array and then sorting the array after the answers are complete slows down the whole function. Using built in JS methods like forEach, map and sort (like I did above), slows the code/function down even more. There is obviously a better and more accurate way to do this, so I'm asking for some JS masterminds to help me out on this.
you can keep adding numbers to a dictionary as keys with values as their index, and as soon as you find a repeating key in the dictionary return its value. This will be O(n) time complexity and O(n) space complexity.
function firstDuplicate(arr) {
var dictionary = {};
for(var i = 0; i < arr.length; i++) {
if(dictionary[arr[i]] !== undefined)
return arr[i];
else
dictionary[arr[i]] = i;
}
return -1;
}
console.log(firstDuplicate([2, 3, 3, 1, 5, 2]));
Since the numbers are between 1 to arr.length you can iterate on the array. For each arr[i] use arr[i] as index and make the element present and arr[arr[i]] negative, then the first arr[arr[i]] negative return arr[i]. This give O(1) space complexity and O(n) time complexity you can do this:
function firstDuplicate(arr) {
for(var i = 0; i < arr.length; i++) {
if(arr[Math.abs(arr[i])] < 0)
return Math.abs(arr[i]);
else
arr[Math.abs(arr[i])] = 0 - arr[Math.abs(arr[i])];
}
return -1;
}
console.log(firstDuplicate([2, 3, 3, 1, 5, 2]));
function firstDuplicate(arr) {
for(var i = 0; i < arr.length; i++) {
var num = Math.abs(arr[i]);
if(arr[num] < 0)
return num;
arr[num] = - arr[num];
}
return -1;
}
console.log(firstDuplicate([2,2,3,1,2]));
function firstDuplicate(arr) {
var numMap = {};
for (var i = 0; i < arr.length; i++) {
if (numMap[arr[i]]) {
return arr[i];
}
numMap[arr[i]] = true;
}
return -1;
}
Answer mentioned by #dij is great, but will fail for [2,2] or [2,3,3],
a little change
for input [2,2], i=0 we get a[ Math.abs[a[0] ] = a[2] = undefined
so we remove 1 from a[ Math.abs[a[0] -1 ] this will work now
function firstDuplicate(arr) {
for(var i = 0; i < arr.length; i++) {
if(arr[Math.abs(arr[i])-1] < 0)
return Math.abs(arr[i]);
else
arr[Math.abs(arr[i])-1] = 0 - arr[Math.abs(arr[i])-1];
}
return -1;
}
Please try the code below:
function getCountOccurence(A) {
let result = [];
A.forEach(elem => {
if (result.length > 0) {
let isOccure = false;
result.some((element) => {
if (element.element == elem) {
element.count++;
isOccure = true;
}
});
if (!isOccure) {
result.push({element: elem, count: 1});
}
} else {
result.push({element: elem, count: 1});
}
});
return result;
}
function getFirstRepeatingElement(A) {
let array = getCountOccurence(A);
array.some((element)=> {
if (element.count > 1) {
result = element.element;
return true;
}
});
return result;
}

Codewars Challenge - Count of positives / sum of negatives

My code works but it's not being accepted in order to pass the challenge. Any help on what I'm doing wrong would be appreciated.
Challenge Description:
Given an array of integers.
Return an array, where the first element is the count of positives numbers and the second element is sum of negative numbers.
If the input array is empty or null, return an empty array:
C#/Java: new int[] {} / new int[0];
C++: std::vector<int>();
JavaScript/CoffeeScript/PHP/Haskell: [];
Rust: Vec::<i32>::new();
ATTENTION!
The passed array should NOT be changed. Read more here.*
For example:
input [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15]
return [10, -65].
My Code:
function countPositivesSumNegatives(input) {
if (input.length < 1){
return [];
}
var newArray = [0, 0];
for (var i = 0; i < input.length; i++){
if (input[i] > 0)
{
newArray[0] += 1;
}
else {
newArray[1] += input[i];
}
}
return newArray;
}
You're not checking for null when the challenge explicitly requires that "if the input array is empty or null, return an empty array". Please consider changing the code as follows
if (input == null || input.length < 1){
return [];
}
This code is working for me (in JavaScript)
function countPositivesSumNegatives(input) {
if (input === null || input.length < 1) {
return [];
}
var array = [0, 0];
for(var i = 0; i < input.length; i++) {
if(input[i] <= 0) {
array[1] += input[i];
} else {
array[0] += 1;
}
}
return array;
}
So, you need check if input === null (and return empty array), and if input[i] <= 0 (to sum of negatives)
Here is an approach I used in Javascript so maybe you can borrow afew ideas off it as well
function countPositivesSumNegatives(input) {
if (input == null || input.length < 1){
return [];
}
var sum =0;
var pos =[];
for (var i=0; i<input.length; i++){
if(input[i]>0){
pos.push(input[i]);
} else{
sum += input[i];
}
}
return [pos.length, sum];
}
Here is my solution for this task:
function countPositivesSumNegatives(input) {
let sumOfPositive = 0;
let sumOfNegative = 0;
if(input == null || input.length < 1) {
return [];
} else {
input.map(item => {
if(item > 0) {
sumOfPositive++;
} else if(item < 0) {
sumOfNegative += item;
} else {
return []
}
})
}
return [sumOfPositive, sumOfNegative]
}
Here is my solution for this task:
function countPositivesSumNegatives (a) {
if (!a || !a.length) return []
let pos = a.filter(x => x > 0),
neg = a.filter(x => x <= 0)
return [pos.length, Math.floor(neg.reduce((s,v)=>s+v,0))]
}
solution for codewars
Meet the longest code in the topic
function countPositivesSumNegatives(input) {
if (input && input.length > 1) {
let count = [];
let sum = [];
for (i=0; i<input.length; i++) {
if (input[i] > 0) {
count.push(input[i]);
} if (input[i] < 0) {
sum.push(input[i]);
}
};
let sumNegatives = 0
for (i=0; i<sum.length; i++) {
sumNegatives += sum[i];
}
let result = [count.length, sumNegatives];
return result;
};
if (input === null || input.length < 1) {
let result = [];
return result;
};
if (input[0] < 0) {
let result = [0, input[0]]
return result
}
}
function countPositivesSumNegatives(input) {
const pos = input.filter((el) => el >= 1).length;
const neg = input.filter((el) => el < 0);
const negSums = neg.reduce((a, b) => a + b, 0);
(input === null || input.length == 0) ? [] : (input.forEach((num) => num > 0 ? pos : []))
const finalArr = [];
finalArr.push(negSums);
finalArr.unshift(pos);
return finalArr;
}
This one definitely works ::
function countPositivesSumNegatives(input) {
let positiveNums = 0;
// initialize positive number variable
let negativeNums = 0;
// initialize negative number variable
if (input === null || input.length === 0) {
return []; // if the input is empty or null, it will return empty array
} else {
input.forEach((num) => num > 0 ? positiveNums++ : negativeNums += num);
}
return [positiveNums , negativeNums];}
For positive numbers, it will add the current number to the previous number and return the latest available value after iterating through the whole array.

Check if string contains substring without using any standard JavaScript methods?

So I need to implement a javascript method which will return true or false depending on if the masterString contains a subString.
I did something like following but not sure if this is the right approach :
function contains(masterString, subString) {
if(subString.length > masterString.length){
return false;
}
for(var i=subString.length-1; i<masterString.length; i++){
if(concatString(i - subString.length-1, i, masterString) === subString){
return true;
}
}
return false;
}
function concatString(index1, index2, string){
var conString = '';
console.log(index1, index2-1, string);
for(var i=index1; i<index2-1; i++){
conString += string[i];
}
console.log(conString);
return conString;
}
contains('abcd', 'bc');
It isn't working fine though.
Can we implement it? Thanks :)
For each possible index, test if subString is on that index of masterString.
var indexOf = function(masterString,subString){
for(var i = 0 ; i < masterString.length - subString.length + 1; i++){
var match = true;
for(var j = 0; j < subString.length; j++){
if(masterString[i + j] !== subString[j]){
match = false;
break;
}
}
if(match)
return i;
}
return -1;
}
var contains = function(master,sub){
return indexOf(master,sub) !== -1;
}
Note: There are faster algorithms to achieve that like Knuth–Morris–Pratt.
You have a good solution. But I think mine is easier.
By the way: I think .length is a javascript funciton too.
function length(string){
var count = 0;
while(string[count] != undefined)
count++;
return count;
}
function contains(masterString, subString) {
var masterStringLength = length(masterString);
var subStringLength = length(subString);
for(var i = 0; i <= masterStringLength - subStringLength; i++)
{
var count = 0;
for(var k = 0; k < subStringLength; k++)
{
if(masterString[i + k] == subString[k])
count++;
else
break;
}
if(count == subStringLength)
return true;
}
return false;
}
console.log(contains('abcdefgh', 'bcde'));
console.log(contains('abcdefgh', 'ab'));
console.log(contains('abcdefgh', 'fgh'));
You can use a nested loop:
function contains(masterString, subString) {
outerloop:
for(var i=0; i <= masterString.length-subString.length; ++i) {
for(var j=0; j<subString.length; ++j)
if(masterString[i + j] !== subString[j]) continue outerloop;
return true;
}
return false;
}
Of course, using native methods you could achieve better performance.
This is similar to longest common subsequence See this.
this code solves your issue.
function contains(masterString, subString) {
if (findCommonSubsequence(masterString, subString) == subString)
alert(true);
else
alert(false);
}
function findCommonSubsequence(a, b) {
var table = [],
aLen = a.length,
bLen = b.length;
squareLen = Math.max(aLen, bLen);
// Initialize a table of zeros
for (var i = 0; i <= squareLen ; i++) {
table.push([]);
for (var j = 0; j <= squareLen; j++) {
table[i][j] = 0;
}
}
// Create a table of counts
for (var i = 1; i <= aLen; i++) {
for (var j = 1; j <= bLen; j++) {
if (a[i - 1] == b[j - 1]) {
table[i][j] = table[i - 1][j - 1] + 1;
} else {
table[i][j] = Math.max(table[i - 1][j], table[i][j - 1]);
}
}
}
// Move backwards along the table
i = aLen, j = bLen, LCS = [];
while (i > 0 && j > 0) {
if (a[i - 1] == b[j - 1]) {
LCS.push(a[i - 1]);
i -= 1;
j -= 1;
} else {
if (table[i][j - 1] >= table[i - 1][j]) {
j -= 1;
} else {
i -= 1;
}
}
}
return(LCS.reverse().join(''));
}
Your question doesn't have enough odd constraints, so let's do it
without for-loops as well, with some help from ES6.
// Cf. Array.prototype.some
const any = (f, [x,...xs]) =>
x === undefined ? false : f(x) || any(f,xs);
// Return true if the first iterable is a prefix of the second.
const isprefix = ([x,...xs], [y,...ys]) =>
x === undefined ? true : x == y && isprefix(xs,ys);
// tails('abc') --> [['a','b','c'], ['b','c'], ['c']]
const tails = ([x,...xs]) =>
x === undefined ? [] : [[x,...xs],...tails(xs)];
// If needle is empty, or is a prefix of any of tails(haystack), return true.
const contains = (haystack, needle) =>
needle.length ? any(bale => isprefix(needle, bale), tails(haystack)) : true;
const tests = [
['aaafoobar', 'foo'],
['foo', 'foo'],
['fo', 'foo'],
['', 'f'],
['f', ''],
['', '']
];
tests.forEach(test => console.log(JSON.stringify(test), contains(test[0], test[1])));
You can do like this
var substr = "test",
masterstr = "test1",
checksubstr = (ms,ss) => !!~ms.indexOf(ss);
console.log(checksubstr(masterstr,substr));

Finding all permutations of a number without duplicates (edited for clarity)

I've finished this challenge from Coderbyte, but inelegantly:
Have the function PrimeChecker(num) take num and return 1 if any
arrangement of num comes out to be a prime number, otherwise return 0.
For example: if num is 910, the output should be 1 because 910 can be
arranged into 109 or 019, both of which are primes.
My solution works by producing an array of all possible permutations of the digits in the num argument, then scanning it for primes:
function PrimeChecker(num) {
// Accounting for 1 not being a prime number by definition
if (num == 1) {
return 0;
}
// Defining an empty array into which all permutations of num will be put
var resultsArray = [];
// Breaking num into an array of single-character strings
var unchangedArray = num.toString().split('');
// Function to push all permutations of num into resultsArray using recursion
function getAllCombos (array, count) {
if (count === num.toString().length) {
return;
}
else {
for (var i = 0; i < array.length; i++) {
var temp = array[count];
array[count] = array[i];
array[i] = temp;
resultsArray.push(array.join(''));
}
return getAllCombos(array, count+1) || getAllCombos(unchangedArray, count+1);
}
}
getAllCombos(unchangedArray, 0);
// Converting the results from strings to numbers and checking for primes
var numArr = [];
resultsArray.forEach(function(val, indx) {
return numArr[indx] = Number(val);
});
for (var i = 0; i < numArr.length; i++) {
var prime = 1;
for (var j = 2; j < numArr[i]; j++) {
if (numArr[i] % j == 0) {
prime = 0;
}
}
if (prime == 1) {
return prime;
}
}
return 0;
}
The problem is that the array of permutations of the num argument which I'm producing is full of duplicates.. I feel like this can be done more efficiently.
For example, running PrimeChecker(123) results in a permutations array of 20 entries, when there only need be 6.
Does anyone have an idea of how to do this more efficiently?
This is how I would do it:
var permute = (function () {
return permute;
function permute(list) {
return list.length ?
list.reduce(permutate, []) :
[[]];
}
function permutate(permutations, item, index, list) {
return permutations.concat(permute(
list.slice(0, index).concat(
list.slice(index + 1)))
.map(concat, [item]));
}
function concat(list) {
return this.concat(list);
}
}());
function isPrime(n) {
for (var i = 2, m = Math.sqrt(n); i <= m; i++)
if (n % i === 0) return false;
return true;
}
function PrimeChecker(num) {
return permute(num.toString(10).split("")).some(function (xs) {
return isPrime(parseInt(xs.join(""), 10));
}) ? 1 : 0;
}
alert(PrimeChecker(910));
Here's the explanation of the algorithm for finding the permutations of the elements of an array.
Hope that helps.

Categories