Move Zeros logic break down Javascript - javascript

I am working through this solution that I saw in this discussion section of leetcode and am unable to grasp part of the logic. The name of the game is to move all zeros to the end of a given array in place while maintaining the order of the other numbers. The increment operator inside the index of j is where I am lost because wouldn't that place the non-zero number to the right?
var moveZeroes = function(nums) {
let j = 0
for(let i = 0; i < nums.length; i++) {
if(nums[i] !== 0) {
//storing the index we are iterating on
let n = nums[i]
//changing the index in place to 0
nums[i] = 0
//console.log(nums);
//
nums[j++] = n
console.log(nums);
}
}
return nums;
};
console.log(moveZeroes([0,1,0,3,12]));

Remember that j++ is post-increment, so the initial value of j is used to index nums and then j is incremented. If it was ++j then j would be incremented first, then used.

Simply Remove All Zeros. Add Removed Zeros to the end.
var moveZeroes = (nums) =>
(
nums.toString().replaceAll("0,", "") +
",0".repeat(("" + nums).replace(/[^0]/g, "").length)
)
.split(",")
.map(Number);
console.log(moveZeroes([0, 1, 0, 0, 3, 0, 12])); //[ 1, 3, 12, 0, 0, 0, 0 ]
NOTE:
(""+nums).replace(/[^0]/g,'').length: number of 0 in the Array
nums.toString(): To convert array to string we use or we could use the trick of concatenating with an empty string like ""+nums
split(','): To convert string into an array
map(Number): To convert an array of strings to numbers.

Update
OP wants to mutate the array, "Solution A" deals with immutable arrays and "Sulution B" nutates the array.
Solution A (Immuatable)
Try using Array.filter() to separate zeroes (ex. num === 0) and numbers that are not zeroes (ex. num !== 0) into two new and separate arrays. Then use either Array.concat() or the spread operator to merge them into a single array.
// log() is an optional utility function that formats console logs
const log = data => console.log(`[${data}]`);
// This input array has zeroes everywhere
const numbers = [0, 1, 0, 0, 3, 0, 12];
const moveZeroes = array => {
// With the given array called "numbers"
// left = [1, 3, 13]
const left = array.filter(num => num !== 0);
// right = [0, 0, 0, 0]
const right = array.filter(num => num === 0);
// Then arrays "left" and "right" are merged
return [].concat(left, right)
};
log(moveZeroes(numbers));
Solution B (Muatable)
Array.reverse() the array, track the index with Array.entries(), and run it through a for...of loop. If a number isn't a zero, Array.splice() it out then Array.unshift() it to the beginning of the array. Note, .reverse(), .splice(), and .unshift() are mutating Array methods.
// log() is an optional utility function that formats console logs
const log = data => console.log(`[${data}]`);
// This input array has zeroes everywhere
const numbers = [0, 1, 0, 0, 3, 0, 12];
const moveZeroes = array => {
/* .reverse() the array, track index with
.entries(), and loop thru with a for...of
loop */
for (let [idx, num] of array.reverse().entries()) {
/* if a number isn't zero, remove it with
.splice(), then .unshift() it into the
beginning of array */
if (num !== 0) {
array.splice(idx, 1);
array.unshift(num);
}
}
return array;
};
log(moveZeroes(numbers));

Related

Appending new keys, and changing values in for/if loop

My current goal is to take items in array integers and create a key pair value based on how many times the key appeared in integers. My logic is: for i in integers, if i is in integers 2 already, increment that key's value by 1. if it doesn't exist, create the key and pair it with a value of 1. It's been a few hours now and after heavy googling I can't seem to find where im messing my logic up.
//require realdine-sync module
var readlineSync = require('readline-sync');
//initialize variable and list
var integer;
integers2 = {};
var integers = [];
//user input
integer = readlineSync.question('Integer?: ')
//check user input and append any integer besides 0
while (integer != 0 && integer >= 1 && integer <= 100){
console.log("not 0!")
integers.push(integer)
integer = readlineSync.question('Integer?: ')
}
console.log(integers);
for(i in integers){if (i in integers2){integers2[i] += 1}else{integers2[i] = 1}
}
console.log(integers2)
let integers2 = {}
integers = [5, 4, 5, 2, 4, 7, 5];
// you were using 'in' instead 'of', 'in': gives you index , 'of'?: gives you value of array
for (let i of integers) {
if (integers2[i]) { // if key exist increment value by one
integers2[i] += 1
} else { // else add 1 as the first value
integers2[i] = 1
}
}
console.log(integers2);
This is a solution that you can try which works. It uses the same logic as you described in the question. This solution uses Array.prototype.reduce() with a Map().
const howMany = arr => arr
.reduce(
(map, n) => map.set(n, (map.get(n) ?? 0) + 1),
new Map()
)
console.log([...howMany([3, 4, 6, 4, 5, 5, 5])])

How to move all zero elements to the center of the array?

Yesterday, I was struggling with a question asked by a company in their pre-screen round. The problem is that you will be given an array of integers. Your task is to move all the elements that have the value of zero into the middle of the array. To make it easier, center = floor(array.length/2).
I already had a solution, but it only works if you have only one zero element in your array.
I hope to receive better answers from you all.
Thank you.
/**
*
* #param {*} arr: a list of integers
* #return: updated list of integers with all zero element moved to the middle
* #example: [4,0,1,1,3] => [4,1,0,1,3]
*/
const zeroesToMid = (arr) => {
const mid = Math.floor(arr.length/2)
let result
for(let i = 0;i < arr.length;i++){
if(arr[i] === 0) {
let firstHalf = arr.splice(0,i)
let secondHalf = arr.splice(i, arr.length)
result = firstHalf.concat(secondHalf)
result.splice(mid,0,0)
}
}
return result
}
Some comments about your attempt:
In each iteration you restart with a result based on arr. So actually you lose the result from every previous iteration.
splice will move several array items: so this is not very efficient, yet you call it several times in each iteration. Moreover, you have at least one conceptual error here:
let firstHalf = arr.splice(0,i)
let secondHalf = arr.splice(i, arr.length)
The first splice will actually remove those entries from arr (making the array shorter), and so the second call to splice will not have the desired result. Maybe you confused splice with slice here (but not later in your code).
If the previous two errors were corrected, then there still is this: after a zero has been moved from index i to a forward position, there is now another value at arr[i]. But as the next iteration of the loop will have incremented i, you will never look at that value, which might have been zero too.
concat creates a new array and you call it in each iteration, making it even more inefficient.
Solution
Better than splicing and concatenating is to copy values without affecting the array size.
If it is necessary that the non-zero values keep their original order, then I would propose the following algorithm:
In a first iteration you could just count the number of zeros. From this you can derive at which range they should be grouped in the result.
In a second iteration you would copy a certain number op non-zero values to the left side of the array. Similarly you would do that at the right side as will. Finally, just fill the center section with zeroes.
So here is an implementation:
function moveZeroes(arr) {
// count zeroes
let numZeroes = 0;
for (let i = 0; i < arr.length; i++) numZeroes += !arr[i];
// Determine target range for those zeroes:
let first = (arr.length - numZeroes) >> 1;
let last = first + numZeroes - 1;
// Move some non-zero values to the left of the array
for (let i = 0, j = 0; i < first; i++, j++) {
while (!arr[j]) j++; // Find next non-zero value
arr[i] = arr[j]; // Move it to right
}
// Move other non-zero values to the right of the array
for (let i = arr.length - 1, j = i; i > last; i--, j--) {
while (!arr[j]) j--; // Find next non-zero value
arr[i] = arr[j]; // Move it to right
}
// Fill the middle section with zeroes:
for (let i = first; i <= last; i++) arr[i] = 0;
return arr;
}
// Demo
console.log(moveZeroes([0, 1, 2, 3, 4, 5, 0, 6, 0, 0]));
NB: If it is not necessary that the non-zero values keep their original order, then you could reduce the number of assignments even more, as you then only need to move the non-zero values that occur in the region where the zeroes should come. The other non-zero values can just stay where they are.
Possible approach:
Problem statement doesn't specify, whether all zeros should be centered exactly (that requires counting zeros first), so we can just squeeze left and right parts, shifting non-zero elements to the corresponding end.
For example, left half might be treated like this sketch
cz = 0;
for(let i = 0; i <= mid;i++) {
if (A[i])
A[i-cz] = A[i];
else
cz++;
}
for(let i = mid - cz + 1; i <= mid;i++) {
A[i] = 0;
}
Now increment mid if cz>0 (so we have already filled central position with zero) and do the same for the right half in reverse direction (backward for-loop, A[i+cz] = A[i]).
Result:
[0, 1, 2, 3, 4, 5, 0, 6, 0, 0] => [1, 2, 3, 4, 0, 0, 0, 0, 5, 6]
As always, trincot does a spot-on analysis of what's wrong with your code.
I have what I think is a simpler solution to the problem though. We can use Array.prototype.filter to select the non-zero entries and then split that in half, then creating an output array by combining the first half with an appropriate number of zeros and then the second half. It might look like this:
const moveZeroes = (
ns,
nonZeroes = ns .filter (n => n !== 0),
len = nonZeroes .length >> 1
) => [
... nonZeroes .slice (0, len),
... Array (ns .length - nonZeroes .length) .fill (0),
... nonZeroes .slice (len)
]
const xs = [0, 1, 2, 3, 4, 5, 0, 6, 0, 0]
console .log (... moveZeroes (xs))
console .log (... xs)
First off, nonZeroes .length >> 1 takes advantage of bit-manipulation to create an expression that is simpler than Math .floor (nonZeroes .length / 2). It's like to be marginally faster too. But they have equivalent behavior.
Notice in the output that the original array did not change. This is very much intentional. I simply much prefer working with immutable data. But if you really want to change the original, we can just use Object.assign, to fold these new values back into the original array:
const moveZeroes = (
ns,
nonZeroes = ns .filter (n => n !== 0),
len = nonZeroes .length >> 1
) => Object .assign (ns, [
... nonZeroes .slice (0, len),
... Array (ns .length - nonZeroes .length) .fill (0),
... nonZeroes .slice (len)
])
const xs = [0, 1, 2, 3, 4, 5, 0, 6, 0, 0]
console .log (... moveZeroes (xs))
console .log (... xs)
Finally, I prefer the style demonstrated here of using only expressions and not statements. But if you don't like the defaulted parameters for extra variables, this could easily be rewritten as follows:
const moveZeroes = (ns) => {
const nonZeroes = ns .filter (n => n !== 0)
const len = nonZeroes .length >> 1
return [
... nonZeroes .slice (0, len),
... Array (ns .length - nonZeroes .length) .fill (0),
... nonZeroes .slice (len)
]
}
and again, we can use Object .assign if we want to.
The big trick here is that we're not actually moving the values, we're extracting some of them, and then simply sticking back together three separate arrays.
here we have to take new array to return the value so it takes space complexity of O(n)
const fun = (arr)=>{
new_array = []
let zero_count = 0
for(let i in arr)
if(!arr[i])
zero_count += 1
let last_index = -1
for(let i = 0; i<arr.length;i++){
if (new_array.length >= Math.floor((arr.length - zero_count)/2)){
last_index = i
break;
}
if(arr[i]) new_array.push(arr[i]);
}
for (let i = 0; i<zero_count;i++)
new_array.push(0)
if (last_index != -1)
for(let i =last_index;i<arr.length;i++)
if(arr[i]) new_array.push(arr[i]);
return new_array
}
console.log(fun([0,1,0,0,2,3,4,0,0]))
resultant output is [1,2,0,0,0,0,0,3,4]
Time Complexity is O(n),
Space Complexity is O(n)

JavaScript: Rearrange an array in order – largest, smallest, 2nd largest, 2nd smallest, 3rd largest, 3rd smallest,

Given an array of integers, where the values should be sorted in the following order:
if we have an array
[1, -1, -3, 9, -2, -5, 4, 8,]
we must rearrange it this way: largest number, smallest number, 2nd largest number, 2nd smallest number, ...
[9, -5, 8, -3, 4, -2, 1, -1 ]
I get the first largest and smallest numbers, but can't figure out how to make it dynamic for all values in the array.
I know that I must take two variables, say firstSmallest and firstLargest and point them to the first and last index of the array respectively, run a loop, which I do already in the code below, and store value into new array by incrementing firstSmallest and decrementing firstLargest, but couldn't implement into code.
let unsortedArr = [1, 5, 8 , 7, 6, -1, -5, 4, 9, 5]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => a-b);
let firstSmallest = sorted[0];
let firstLargest = sorted[unsorted.length-1];
for(let i = 0; i <= sorted.length; i++){
//I should increment firstSmallest and decrement firstLargest numbers and store in output
}
return output;
}
meanderArray(unsortedArr);
console.log(output);
You could take a toggle object which takes the property of either the first item or last from an array and iterate until no more items are available.
function meanderArray([...array]) {
const
result = [],
toggle = { shift: 'pop', pop: 'shift' };
let fn = 'shift';
array.sort((a, b) => a - b);
while (array.length) result.push(array[fn = toggle[fn]]());
return result;
}
console.log(...meanderArray([1, 5, 8, 7, 6, -1, -5, 4, 9, 5]));
You can sort an array by descending, then logic is the following: take first from start and first from end, then second from start-second from end, etc.
let unsortedArr = [1, 5, 8 , 7, 6, -1, -5, 4, 9, 5]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => b-a);
let output = []
for(let i = 0; i < sorted.length/2; i++){
output.push(sorted[i])
if(i !== sorted.length - 1 - i){
output.push(sorted[sorted.length - 1 - i])
}
}
return output;
}
let result = meanderArray(unsortedArr);
console.log(result);
You can sort, then loop and extract the last number with pop() and extract the first number with shift().
let unsortedArr = [1, -1, -3, 9, -2, -5, 4, 8,]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => a - b);
for(let i = 0; i < unsortedArr.length + 2; i++){
output.push(sorted.pop());
output.push(sorted.shift());
}
console.log(output);
return output;
}
meanderArray(unsortedArr);
Fastest Meandering Array method among all solutions mentioned above.
According to the JSBench.me, this solution is the fastest and for your reference i have attached a screenshot below.
I got a different approach, but i found that was very close to one of above answers from elvira.genkel.
In my solution for Meandering Array, First I sorted the given array and then i tried to find the middle of the array. After that i divided sorted array in to two arrays, which are indices from 0 to middle index and other one is from middle index to full length of sorted array.
We need to make sure that first half of array's length is greater than the second array. Other wise when applying for() loop as next step newly created array will contains some undefined values. For avoiding this issue i have incremented first array length by one.
So, always it should be firstArr.length > secondArr.length.
And planned to create new array with values in meandering order. As next step I created for() loop and try to push values from beginning of the first array and from end of the second array. Make sure that dynamically created index of second array will receive only zero or positive index. Other wise you can find undefined values inside newly created Meandering Array.
Hope this solution will be helpful for everyone, who loves to do high performance coding :)
Your comments and suggestions are welcome.
const unsorted = [1, 5, 8, 7, 6, -1, -5, 4, 9, 5];
const sorted = unsorted.sort((a,b)=>a-b).reverse();
const half = Math.round(Math.floor(sorted.length/2)) + 1;
const leftArr = sorted.slice(0, half);
const rightArr = sorted.slice(half, sorted.length);
const newArr = [];
for(let i=0; i<leftArr.length; i++) {
newArr.push(leftArr[i]);
if (rightArr.length-1-i >= 0) {
newArr.push(rightArr[rightArr.length-1-i]);
}
}

Sort an array in a peculiar order

I've been trying to figure out how to solve this problem but I can't seem to find the proper sorting order.
Instructions:
Write a program that orders a list of numbers in the following way:
3,-2,1,0,-1,0,-2,1 => -2,-1,-2,0,0,3,1,1
'use strict';
let myNumbers = '3,-2,1,0,-1,0,-2,1';
// I receive the input as a string and split and map it into an array
let myNumbers = gets().split(',').map(Number);
I've tried applying the sort() method in ascending order to all integers below zero and doing the opposite for those above but that's not quite the order in the expected output.
I've also attempted to splice the first array after applying sort() to 0 and then re-arrange the spliced part and concatenate it. However, that won't work with all test inputs.
Another example:
3,-12,0,0,13,5,1,0,-2 => -12,-2,0,0,0,3,13,5,1
What is the logic in this order? Thanks.
Because this sounds like the solution to a homework problem or something of the like, I'll let you write the code:) But the way I would do it is in one iteration through the array, create three separate arrays:
Negative numbers
0s
Positive numbers
Squish the arrays together without sorting and you have your O(N) solution.
So based on sketrik answer which covers the logic, this is the code:
const myNumbers = '3,-2,1,0,-1,0,-2,1';
const arr = myNumbers.split(',').map(Number)
const res = arr.filter(i => i < 0)
.concat(arr.filter(i => i === 0))
.concat(arr.filter(i => i > 0))
console.log(res)
This works thanks to two very basic JS methods of Array.prototype:
concat and filter. I could not explain them better than the documentation, check it out!
But basically, what I am doing is:
find the chunk with negatives with arr.filter(i => i < 0)
find the chunk with zeros with arr.filter(i => i === 0)
find the chunk with positives with arr.filter(i => i > 0)
concat them all into one array.
I am Neo.
'use strict';
let myInput = '3,-2,1,0,-1,0,-2,1';
let myNumbers = myInput.split(',').map(Number);
let negatives = [];
let zeroes = [];
let positives = [];
for (const element of myNumbers) {
if (element < 0) {
negatives.push(element);
} else if (element === 0) {
zeroes.push(element);
} else if (element > 0) {
positives.push(element);
}
}
let sortedArr = negatives.concat(zeroes, positives);
console.log(sortedArr.join(','));
Logic or Typo?
"...ascending order to all integers below zero and doing the opposite for those above..."
Following what was posted in question the examples should be:
-2, -2, -1, 0, 0, 3, 1, 1 and -12, -2, 0, 0, 0, 13, 5, 3, 1
Zero and less ascending: -3, -2, -1, 0. Greater than zero descending: 3, 2, 1
To get those results see Demo 1.
Strictly going by the examples is simpler:
-2, -1, -2, 0, 0, 3, 1, 1 and -12, -2, 0, 0, 0, 3, 13, 5, 1
Group negative numbers, then zeros, and then positive numbers: [-][0][+]. No order within the three arrays is required. Order is only required for the three groups.
To get those results see Demo 2.
Explanation
Demo 1
First, sort array in ascending order:
const ordered = array.sort((current, next) => current - next);
Next, find the index of the first number that's greater than 0, then extract all numbers beginning at that index and ending at the last number. Store the extracted array in a variable:
const positive = ordered.splice(ordered.findIndex(number => number > 0));
Finally, sort extracted array in descending order and then concatenate the extracted array to the end of the original array:
return ordered.concat(positive.sort((current, next) => next - current));
Demo 2
Create three new arrays returned by the filter() method: negative (n < 0), zero (n === 0), and positive (n > 0).
Then concatenate them into one array:
const negative = array.filter(number => number < 0);
const zero = array.filter(number => number === 0);
const positive = array.filter(number => number > 0);
return negative.concat(zero, positive);
Demo 1
const unorderedA = [3, -2, 1, 0, -1, 0, -2, 1];
const unorderedB = [3, -12, 0, 0, 13, 5, 1, 0, -2];
const illogical = array => {
const ordered = array.sort((current, next) => current - next);
const positive = ordered.splice(ordered.findIndex(number => number > 0));
return ordered.concat(positive.sort((current, next) => next - current));
};
// For demonstration purposes
const log = data => {
const string = Array.isArray(data) ? `[${data.join(', ')}]` : data;
return console.log(string);
};
log(illogical(unorderedA));
log(illogical(unorderedB));
Demo 2
const unorderedA = [3, -2, 1, 0, -1, 0, -2, 1];
const unorderedB = [3, -12, 0, 0, 13, 5, 1, 0, -2];
const illogical = array => {
const negative = array.filter(number => number < 0);
const zero = array.filter(number => number === 0);
const positive = array.filter(number => number > 0);
return negative.concat(zero, positive);
};
// For demonstration purposes
const log = data => {
const string = Array.isArray(data) ? `[${data.join(', ')}]` : data;
return console.log(string);
};
log(illogical(unorderedA));
log(illogical(unorderedB));

how to check each element in an array for a specific condition

I have six integers stored in an array:
[2,3,4,5,6,7]
I would like to use each item in the array to check against a range of other integers 100 - 999 (i.e. all three-digit numbers) to find a number that has a remainder of 1 when divided by all the items in the array individually.
I'm not sure what javascript method to use for this. I'm trying a for loop:
function hasRemainder() {
let arr = [2,3,4,5,6,7];
for (i = 100; i < 999; i++) {
if (i % arr[0] == 1) {
return i;
}
}
}
but it has several problems I need to solve.
Instead of referring to a particular item e.g. arr[0], I need to find a way to loop through all the items in the array.
Currently, this function only returns one number (the loop stops at the first number with a remainder), but I need all the possible values in the given range.
If anyone could help with these two problems, I'd really appreciate it. Thanks.
You could map an array of values and then filter the array by checking every remainder value with one.
function hasRemainder() {
var array = [2, 3, 4, 5, 6, 7];
return Array
.from({ length: 900 }, (_, i) => i + 100)
.filter(a => array.every(b => a % b === 1));
}
console.log(hasRemainder())
This works also;
function hasRemainder() {
const arr = [2, 3, 4, 5, 6, 7];
const remainders = []
for (i = 100; i < 999; i++) {
const isRemainder = arr.every(numb => i % numb === 1)
if (isRemainder) {
remainders.push(i)
}
}
return remainders
}

Categories