Javascript Heap's algorithm (non-recursive) - javascript

I have implemented Heap's non-recursive algorithm in JavaScript.
When checking permutations with console.log(arr) everything works as expected.
But when I try to push each permutation to a result array, then everything breaks up. It just returns result filled with last iteration permutation.
function generate(n, arr) {
function swap(item1, item2){
console.log(item1, item2);
let tmp = arr[item1];
arr[item1] = arr[item2];
arr[item2] = tmp;
}
var c = [];
var allPermutations = [];
for (let i = 0; i < n; i++) {
c[i] = 0;
}
console.log(arr);
allPermutations.push(arr);
for (let i = 1; i < n; i) {
if (c[i] < i) {
if (i % 2 == 0) {
swap(0, i);
} else {
swap(c[i], i);
}
console.log(arr);
allPermutations.push(arr);
c[i] += 1;
i = 1;
} else {
c[i] = 0;
i += 1;
}
}
return allPermutations;
}
console.log('result', generate(3, ["a", "a", "b"]));

The problem is that arrays are just references so when you push in the array you are just pushing a reference to it. So, on the next iteration you update the array and when you look at the final output, all the indexes will be the same since it is the same array.
So what can you do? clone it.
allPermutations.push(arr.slice(0));

Yep - its a reference problem. Alternative to epascarello's answer:
allPermutations.push([...arr]);

Related

Remove Duplicates from Sorted Array JS

I'm trying to understand why my solution to this problem is only partially working.
Problem:
Given a sorted array nums, remove the duplicates in-place such that each element appears only once and returns the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
My Solution:
var removeDuplicates = function(nums) {
if (nums.length === 0) return 0;
for (let i = 1; i <= nums.length; i++){
if(nums[i] === nums[i-1]){
nums.splice(nums[i], 1);
}
}
return nums.length;
};
This is the outcome I'm getting on leetcode but I don't understand why my solution stops working and the '3s' are not removed?
Output screenshot:
When you splice an array while iterating over it, the whole array will change in-place. For example, let's say that indexes 0 and 1 are duplicates (i is 1). Then, if you remove index 1 from the array, what used to be at index 2 will now be at index 1, and what used to be at index 3 will now be at index 2, etc.
So, you need to subtract 1 from i when an element is removed, otherwise the next element will be skipped.
You also have an off-by-one-error - iterate i from 1 to i < nums.length so you don't go past the end of the array.
You also need to pass the index to remove to splice, not the value to remove.
var removeDuplicates = function(nums) {
for (let i = 1; i < nums.length; i++){
if(nums[i] === nums[i-1]){
nums.splice(i, 1);
i--;
}
}
return nums.length;
};
console.log(removeDuplicates([0, 0, 0]));
Simple version. Using functions already created
let array = new Set(nums);
let values = array.values();
return Array.from(values);
This'd also pass just fine on constant memory:
const removeDuplicates = function (nums) {
let count = 0;
nums.forEach(function (num) {
if (num !== nums[count]) {
nums[++count] = num;
}
});
return nums.length && count + 1;
};
function removeDuplicates(nums) {
let i = 0;
while(i < nums.length - 1) {
i += 1 - ((nums[i] === nums[i+1]) && nums.splice(i, 1).length)
}
return nums.length;
}
C# simple solution:
public int RemoveDuplicates(int[] nums) {
if (nums.Length == 0)
return 0;
var i = 0;
var start = 0;
var end = 0;
while (end < nums.Length)
{
if (nums[start] != nums[end])
{
nums[++i] = nums[end];
start = end;
}
end++;
}
return i + 1;
}

How to code all for all cases of Two Sum javascript problem

I have been working on the two sum problem for the past few hours and can't seem to account for the case where there are only two numbers and their sum is the same as the first number doubled.
The result should be [0,1], but i'm getting [0,0].
let nums = [3,3];
let targetNum = 6;
function twoSum(nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let b = i+1; b < nums.length; b++) {
if ((nums[i] + nums[b]) == target) {
return [nums.indexOf(nums[i]), nums.indexOf(nums[b])];
}
}
}
}
console.log(twoSum(nums, targetNum))
Two Sum
My approach uses a javascript object and completes the algorithm in O(n) time complexity.
const twoSum = (nums, target) => {
let hash = {}
for(i=0;i<nums.length;i++) {
if (hash[nums[i]]!==undefined) {
return [hash[nums[i]], i];
}
hash[target-nums[i]] = i;
}
};
console.log(twoSum([2,7,11,15], 9)); // example
This is not the way to solve the problem. Step through the array and save the complement of the target wrt the number in the array. This will also solve your corner case.
You should consider, indexOf(i) -> start from the first element, returns the index when match found! That is why in your code, nums.indexOf(nums[i]) and nums.indexOf(nums[b]) which is basically 3 in all two cases, it will return 0, cause 3 is the first element in array.
instead of doing this, return the index itself.
let nums = [3,3];
let targetNum = 6;
function twoSum(nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let b = i+1; b < nums.length; b++) {
if ((nums[i] + nums[b]) == target) {
return i + "" +b;
}
}
}
}
console.log(twoSum(nums, targetNum))

array function that generates array with subset range of numbers

I am trying to create a function that builds an array up to a number set by the function parameter, with an if condition on being included based on whether the remainder is zero. The last number in the array should be no higher than the parameter. Here's what I came up with so far --
function justThreesUpTo(num) {
var array = [];
array.length = num;
for (i = 1; i < array.length; i++) {
if(i % 3 === 0){
array.push(i);
}
else i;
}
array.splice(0, num);
return array;
}
When I console log this, with justThreesUpTo(20), I get --
// [ 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42 ]
I see the issue being setting the limiter at array.length, which maxes out the number of items that can be in the array, but I can't figure out what else to call to make sure the last number in the array goes no higher than the "num" parameter specified by the function call. Any ideas?
Setting an array's length to something before the array is populated isn't a great idea - better to just iterate over the num itself. For example
for (var i = 1; i < num; i++) {
// push to array if i % 3 === 0
Your else i won't do anything - you can just leave it off completely.
You could make your code a whole lot shorter and cleaner if you wanted:
function justThreesUpTo(num) {
const length = Math.floor(num / 3);
return Array.from({ length }, (_, i) => (i + 1) * 3);
}
console.log(justThreesUpTo(20));
Modifying an array while looping over it (or its indices, which is what you’re doing with i < array.length) is a recipe for confusion. Start with an empty array and compare with num instead:
function justThreesUpTo(num) {
var array = [];
for (var i = 1; i < num; i++) {
if (i % 3 === 0) {
array.push(i);
}
}
return array;
}
Now you can optimize the check out of that entirely by moving up the appropriate amount each time.
function justThreesUpTo(num) {
var array = [];
for (var i = 3; i < num; i += 3) {
array.push(i);
}
return array;
}
(In your original code, the entire first num holes created by array.length = num; are unused and get spliced off, and else i does nothing.)
You can try with a simple while loop
function justThreesUpTo(num) {
var array = [];
var i = 0;
while (i < num) {
if(i % 3 === 0){
array.push(i);
}
i++;
}
return array;
}
console.log(justThreesUpTo(20));
You can use map method and spread syntax in order to write a clean solution.
function justThreesUpTo(num) {
return [ ...Array(Math.floor(num/3)).keys() ].map((_,i)=> (i+1) * 3);
}
console.log(justThreesUpTo(20));
Hmm. Looks like it was a pretty simple solution. Changed the limiter from "array.length" to "num", and it worked fine.
function justThreesUpTo(num) {
var array = [];
array.length = num;
for (i = 1; i < num; i++) {
if(i % 3 === 0){
array.push(i);
}
else i;
}
array.splice(0, num);
return array;
}
Never mind!
Use while with i+=3; inside the while loop:
function justThreesUpTo(num) {
var array = [];
var i = 0;
while(i<num){
array.push(i);
i+=3;
}
return array;
}
console.log(justThreesUpTo(20));

Looping through array using splice method infinite loop javascript

When i loop through the array using the splice method, the page just freezes. It looks like i caused an infinite loop. lib.randomInt() works, so that is not the problem.
function() {
return function(string) {
var arr = string.split("")
arr.sort();
for(var i = 0; arr.length;i++){
arr.splice((i+1),0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
}
})()("example");
This is from a different file that is placed above the main file in html
var lib = {
factorial: function(num){
function _factorial(num){
if(num === 1){
return 1;
} else {
return num*_factorial(num-1);
}
}
console.log(num+"! = " + _factorial(num));
},
randomInt: function(int,offset){
if(offset == undefined || null || NaN){
offset = 0;
}
return Math.floor(Math.random()*int)+offset;
},
display: function(m, fn){
fn(m);
}
};
You've got to loop in reverse when modifying the array itself to avoid corrupting the loop like this...
for (var i=arr.length-1; i>=0; i--){}
I guess that you wanted to insert a random value after every array element, so that the string "example" would become something like "e5x9a2m4p7l1e3"
There are two issues:
Your for loop has no end condition that will become false. You need to state i < arr.length instead of just arr.length which is always truthy for non-empty arrays.
You add array elements in every iteration, but then also visit them in the next iteration, and from there on you will only be visiting the new inserted values and never get to the next original element that keeps being 1 index away from i. You need to increment i once more. For that you can use ++i instead if i+1 as the splice argument.
So your loop should be:
for(var i = 0; i < arr.length; i++) {
arr.splice(++i,0,lib.randomInt(9));
}
const lib = { randomInt: n => Math.floor(Math.random()*n) };
(function() {
return function(string) {
var arr = string.split("")
arr.sort();
for(var i = 0; i < arr.length; i++) {
arr.splice(++i,0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
console.log(pseudocryptarr);
}
})()("example");
Or to save an addition:
for(var i = 1; i <= arr.length; i+=2) {
arr.splice(i,0,lib.randomInt(9));
}
const lib = { randomInt: n => Math.floor(Math.random()*n) };
(function() {
return function(string) {
var arr = string.split("")
arr.sort();
for(var i = 1; i <= arr.length; i+=2) {
arr.splice(i,0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
console.log(pseudocryptarr);
}
})()("example");
I fixed it. I wanted after each character for there to be a number. Using the pre-looped array length and doubling it while iterating twice, means that the splice adds the number after the new number element and then the character.
Edit: My typo was the problem. I didnt even have to use len, just iterate by 2.
for(var i = 0;i < arr.length;i+=2){
arr.splice((i+1),0,lib.randomInt(9));
}
(function() {
return function(string) {
var arr = string.split("")
arr.sort();
var len = arr.length
for(var i = 0;i < len*2;i+=2){
arr.splice((i+1),0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
console.log(pseudocryptarr);
}
})()("example");
Edit: user4723924 method is better:
(function() {
return function(string) {
var arr = string.split("")
arr.sort();
for(var i = arr.length;i >= 0;i--){
arr.splice((i+1),0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
console.log(pseudocryptarr);
}
})()("example");

javascript reverse an array without using reverse()

I want to reverse an array without using reverse() function like this:
function reverse(array){
var output = [];
for (var i = 0; i<= array.length; i++){
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
However, the it shows [7, 6, 5, 4] Can someone tell me, why my reverse function is wrong? Thanks in advance!
array.pop() removes the popped element from the array, reducing its size by one. Once you're at i === 4, your break condition no longer evaluates to true and the loop ends.
One possible solution:
function reverse(array) {
var output = [];
while (array.length) {
output.push(array.pop());
}
return output;
}
console.log(reverse([1, 2, 3, 4, 5, 6, 7]));
You can make use of Array.prototype.reduceright and reverse it
check the following snippet
var arr = ([1, 2, 3, 4, 5, 6, 7]).reduceRight(function(previous, current) {
previous.push(current);
return previous;
}, []);
console.log(arr);
In ES6 this could be written as
reverse = (array) => array.map(array.pop, [... array]);
No need to pop anything... Just iterate through the existing array in reverse order to make your new one.
function reverse(array){
var output = [];
for (var i = array.length - 1; i> -1; i--){
output.push(array[i]);
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
Edit after answer got accepted.
A link in a comment on your opening post made me test my way VS the accepted answer's way. I was pleased to see that my way, at least in my case, turned out to be faster every single time. By a small margin but, faster non the less.
Here's the copy/paste of what I used to test it (tested from Firefox developer scratch pad):
function reverseMyWay(array){
var output = [];
for (var i = array.length - 1; i> -1; i--){
output.push(array[i]);
}
return output;
}
function reverseTheirWay(array) {
var output = [];
while (array.length) {
output.push(array.pop());
}
return output;
}
function JustDoIt(){
console.log("their way starts")
var startOf = new Date().getTime();
for(var p = 0; p < 10000; p++)
{
console.log(reverseTheirWay([7,6,5,4,3,2,1]))
}
var endOf = new Date().getTime();
console.log("ran for " + (endOf - startOf) + " ms");
console.log("their way ends")
}
function JustDoIMyWay(){
console.log("my way starts")
var startOf = new Date().getTime();
for(var p = 0; p < 10000; p++)
{
console.log(reverseMyWay([7,6,5,4,3,2,1]))
}
var endOf = new Date().getTime();
console.log("ran for " + (endOf - startOf) + " ms");
console.log("my way ends")
}
JustDoIt();
JustDoIMyWay();
Solution to reverse an array without using built-in function and extra space.
let arr = [1, 2, 3, 4, 5, 6, 7];
let n = arr.length-1;
for(let i=0; i<=n/2; i++) {
let temp = arr[i];
arr[i] = arr[n-i];
arr[n-i] = temp;
}
console.log(arr);
Do it in a reverse way, Because when you do .pop() every time the array's length got affected.
function reverse(array){
var output = [];
for (var i = array.length; i > 0; i--){
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
Or you could cache the length of the array in a variable before popping out from the array,
function reverse(array){
var output = [];
for (var i = 0, len= array.length; i< len; i++){
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
You are modifying the existing array with your reverse function, which is affecting array.length.
Don't pop off the array, just access the item in the array and unshift the item on the new array so that the first element of the existing array becomes the last element of the new array:
function reverse(array){
var output = [],
i;
for (i = 0; i < array.length; i++){
output.unshift(array[i]);
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
If you'd like to modify the array in-place similar to how Array.prototype.reverse does (it's generally inadvisable to cause side-effects), you can splice the array, and unshift the item back on at the beginning:
function reverse(array) {
var i,
tmp;
for (i = 1; i < array.length; i++) {
tmp = array.splice(i, 1)[0];
array.unshift(tmp);
}
return array;
}
var a = [1, 2, 3, 4, 5];
console.log('reverse result', reverse(a));
console.log('a', a);
This piece allows to reverse the array in place, without pop, splice, or push.
var arr = [1, 2, 3, 4, 5];
function reverseArrayInPlace(arr2) {
var half = Math.floor(arr2.length / 2);
for (var i = 0; i < half; i++) {
var temp = arr2[arr2.length - 1 - i];
arr2[arr2.length - 1 - i] = arr2[i];
arr2[i] = temp;
}
return arr2;
}
As you pop items off the first array, it's length changes and your loop count is shortened. You need to cache the original length of the original array so that the loop will run the correct amount of times.
function reverse(array){
var output = [];
var len = array.length;
for (var i = 0; i< len; i++){
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
You're modifying the original array and changing it's size. instead of a for loop you could use a while
function reverse(array){
var output = [];
while(array.length){
//this removes the last element making the length smaller
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
function rvrc(arr) {
for (let i = 0; i < arr.length / 2; i++) {
const buffer = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = buffer;
}
};
const reverse = (array)=>{
var output = [];
for(let i=array.length; i>0; i--){
output.push(array.pop());
}
console.log(output);
}
reverse([1, 2, 3, 4, 5, 6, 7, 8]);
This happens because every time you do array.pop(), whilst it does return the last index in the array, it also removes it from the array. The loop recalculates the length of the array at each iteration. Because the array gets 1 index shorter at each iteration, you get a much shorter array returned from the function.
This piece of code will work without using a second array. It is using the built in method splice.
function reverse(array){
for (let i = 0; i < array.length; i++) {
array.splice(i, 0, array.splice(array.length - 1)[0]);
}
return array;
}
Here, let's define the function
function rev(arr) {
const na = [];
for (let i=0; i<arr.length; i++) {
na.push(arr[arr.length-i])
}
return na;
}
Let's say your array is defined as 'abca' and contains ['a','b','c','d','e','foo','bar']
We would do:
var reva = rev(abca)
This would make 'reva' return ['bar','foo','e','d','c','b','a'].
I hope I helped!
You can use .map as it is perfect for this situation and is only 1 line:
const reverse = a =>{ i=a.length; return a.map(_=>a[i-=1]) }
This will take the array, and for each index, change it to the length of the array - index, or the opposite side of the array.
with reverse for loop
let array = ["ahmet", "mehmet", "aslı"]
length = array.length
newArray = [];
for (let i = length-1; i >-1; i--) {
newArray.push(array[i])
}
console.log(newArray)
And this one:
function reverseArray(arr) {
let top = arr.length - 1;
let bottom = 0;
let swap = 0;
while (top - bottom >= 1) {
swap = arr[bottom];
arr[bottom] = arr[top];
arr[top] = swap;
bottom++;
top--;
}
}
function reverse(arr) {
for (let i = 0; i < arr.length - 1; i++) {
arr.splice(i, 0, arr.pop())
}
return arr;
}
console.log(reverse([1, 2, 3, 4, 5]))
//without another array
reverse=a=>a.map((x,y)=>a[a.length-1-y])
reverse=a=>a.map((x,y)=>a[a.length-1-y])
console.log(reverse(["Works","It","One","Line"]))
One of shortest:
let reverse = arr = arr.map(arr.pop, [...arr])
This is an old question, but someone may find this helpful.
There are two main ways to do it:
First, out of place, you basically push the last element to a new array, and use the new array:
function arrReverse(arr) {
let newArr = [];
for(let i = 0; i<arr.length; i++){
newArr.push(arr.length -1 -i);
}
return newArr;
}
arrReverse([0,1,2,3,4,5,6,7,8,9]);
Then there's in place. This is a bit tricky, but the way I think of it is like having four objects in front of you. You need to hold the first in your hand, then move the last item to the first place, and then place the item in your hand in the last place.
Afterwards, you increase the leftmost side by one and decrease the rightmost side by one:
function reverseArr(arr) {
let lh;
for(let i = 0; i<arr.length/2; i++){
lh = arr[i];
arr[i] = arr[arr.length -i -1];
arr[arr.length -i -1] = lh;
}
return arr;
}
reverseArr([0,1,2,3,4,5,6,7,8,9]);
Like so. I even named my variable lh for "left hand" to help the idea along.
Understanding arrays is massively important, and figuring out how they work will not only save you from unnecessarily long and tedious ways of solving this, but will also help you grasp certain data concepts way better!
I found a way of reversing the array this way:
function reverse(arr){
for (let i = arr.length-1; i >= 0; i--){
arr.splice(i, 0, arr.shift());
}
return arr;
}
Without Using any Pre-define function
const reverseArray = (array) => {
for (let i = 0; i < Math.floor(array.length / 2); i++) {
[array[i], array[array.length - i - 1]] = [
array[array.length - i - 1],
array[i]
];
}
return array;
};
let array = [1,2,3,4,5,6];
const reverse = (array) => {
let reversed = [];
for(let i = array.length - 1; i >= 0; i--){
reversed[array.length - i] = array[i];
}
return reversed;
}
console.log(reverse(array))
you can use the two pointers approach
example
function reverseArrayTwoPointers(arr = [1, 2, 3, 4, 5]) {
let p1 = 0;
let p2 = arr.length - 1;
while (p2 > p1) {
const temp = arr[p1];
arr[p1] = arr[p2];
arr[p2] = temp;
p1++;
p2--;
}
return arr;
}
to return [5,4,3,2,1]
example on vscode
let checkValue = ["h","a","p","p","y"]
let reverseValue = [];
checkValue.map((data, i) => {
x = checkValue.length - (i + 1);
reverseValue[x] = data;
})
function reverse(str1) {
let newstr = [];
let count = 0;
for (let i = str1.length - 1; i >= 0; i--) {
newstr[count] = str1[i];
count++;
}
return newstr;
}
reverse(['x','y','z']);
Array=[2,3,4,5]
for(var i=0;i<Array.length/2;i++){
var temp =Array[i];
Array[i]=Array[Array.length-i-1]
Array[Array.length-i-1]=temp
}
console.log(Array) //[5,4,3,2]

Categories

Resources