HackerRank - Minimum Swaps 2 Timeout - javascript

This challenge asks that you find the minimum number of swaps to sort an array of jumbled consecutive digits to ascending order. So far my code passes most of the tests, however there are four that fail due to timeout. Could anyone explain why my code is timing out? Is there a way to make it find an answer faster?
function minimumSwaps(arr) {
const min = Math.min(...arr);
let swapCount = 0;
const swap = (array, a, b) => {
let test = array[a];
array[a] = array[b];
array[b] = test;
}
for(let i=0; i<arr.length; i++){
if(arr[i]!==i+min){
swap(arr, i, arr.indexOf(i+min));
swapCount++;
}
}
return swapCount;
}
I thought it was a good solution since it only has to iterate over the length of the array once? I'd love to be able to understand why this isn't performing well enough

Your big issue is with the call to arr.indexOf, as that has to scan the entire array each time you do a swap. You can work around that by generating a reverse lookup from value to array index before starting to sort, and then maintaining that list during the sort. Note that you don't need to do a full swap, only copy the value from arr[i] to its correct place in the array since you don't revisit a number once you have passed it. Also you don't need min, as under the conditions of the question it is guaranteed to be 1, and you don't need to look at the last value in the array since by the time you get to it it has to be correct.
function minimumSwaps(arr) {
const indexes = arr.reduce((c, v, i) => (c[v] = i, c), []);
const len = arr.length - 1;
let swapCount = 0;
for (let i = 0; i < len; i++) {
if (arr[i] !== i + 1) {
arr[indexes[i+1]] = arr[i];
indexes[arr[i]] = indexes[i+1];
swapCount++;
}
}
return swapCount;
}
console.log(minimumSwaps([7, 1, 3, 2, 4, 5, 6]));
console.log(minimumSwaps([4, 3, 1, 2]));
console.log(minimumSwaps([2, 3, 4, 1, 5]));
console.log(minimumSwaps([1, 3, 5, 2, 4, 6, 7]));

I think we should flip function not search function.
function minimumSwaps($arr) {
$outp = 0;
$result = array_flip($arr);
for($i=0; $i<count($arr); $i++){
if($arr[$i] != $i +1){
$keyswp = $result[$i + 1];
$temp = $arr[$i];
$arr[$i] = $i + 1;
$arr[$keyswp] = $temp;
$tempr = $result[$i + 1];
$result[$i + 1] = $i +1;
$result[$temp] = $keyswp;
$outp = $outp + 1;
}
}
return $outp;
}

Here is my solution , it is similar to Nick's except instead of the Array.Proptytype.indexOf method I used an object literal to map the indices of each value for a better Time complexity since search in object literal is O(1) (You can use ES6 maps too). Here is the code
function minimumSwaps(arr) {
let count = 0;
let search = arr.reduce((o, e, i) => {
o[e] = i
return o
}, {})
for(let i =0 ; i < arr.length - 1; i++){
let j = search[i+1]
if(arr[i] !== i+1) {
[arr[i], arr[j]] = [arr[j], arr[i]]
search[arr[i]] = i;
search[arr[j]] = j;
count += 1
}
}
console.log(arr)
return count
}

As suggested by others, you shouldn't use the indexOf method as it makes your solution O(n^2) (As the indexOf method has to scan the entire array again). You can create a position map array before hand and use it later during the swap. It will keep your solution linear. Here is the detailed explanation and solution to the HackerRank Minimum Swaps 2 Problem in java, c, c++ and js, using this method.

Related

Remove Duplicates from Sorted Array (different final results)

I am new at Programing and learning Javascript by doing some exercises from leetcode.com.
I wanted to write a code to remove duplicates in a sorted array.
When I use "console.log" at the end of the function to show the final result, I get the expected result. However when I use return (with the same variable) I get a wrong result. Can anybody please tell me, where I went wrong?
Hier is my code:
/**
* #param {number[]} nums
* #return {number}
*/
var removeDuplicates = function (nums) {
var newNums = []
if (nums.length == 0) {
newNums = []
}
for (var i = 0; i < nums.length; i++) {
var curr = nums[i]
var next = nums[i + 1]
if (curr != next) {
newNums.push(curr)
}
}
console.log(newNums)
return newNums
};
And here is a picture with the code and the results. the green arrow shows the output of (console.log), and the red one shows the output of (return).
Thank you in advance!
A slightly different approach by keeping the original object reference to the array and mutating the array by copying and adjusting the length of the array.
This approach does not need another array.
It basically checks if the predecessor is unequal to the actual item and copies the item to a new index j. This variable has the final length of the array and truncates the unwanted rest of the array.
function removeDuplicates(array) {
let j = 0;
for (let i = 0; i < array.length; i++) {
if (array[i - 1] !== array[i]) array[j++] = array[i];
}
array.length = j;
return array;
}
console.log(removeDuplicates([0, 1, 1, 2, 2, 2, 2, 3, 4, 5, 5]));
Here's how you can remove duplicates in any(sorted or unsorted) array in Javascript
const removeDuplicates = (orignalArray) =>{
let allUniqueArray=[];
let repWordArray=orignalArray.slice();
const removeAnElement=(array, elem)=>{
const index = array.indexOf(elem);
if (index > -1) {
array.splice(index, 1);
}
return array;
}
orignalArray.forEach(elem=>{
if(!allUniqueArray.includes(elem)){
allUniqueArray.push(elem);
repWordArray=removeAnElement(repWordArray,elem)
}
});
return allUniqueArray;
};
let array=[1,2,3,3,4,5,6,6,7];
const uniqueArray = removeDuplicates(array);
console.log('array: ',array);
console.log('uniqueArray: ',uniqueArray);

Big O time efficiency for a quadratic function in JavaScript

I am trying to increase the efficiency of a function. It is currently quadratic and I would like to make it logarithmic.
The third to last line of the current function is confusing me somewhat as well and I would like some clarification.
function solution(arr){
let result = 0
for ( let i = 0; i < arr.length; i++)
for (let j = 0; j < arr.length; j++)
if (arr[i] == arr[j])
result = Math.max(result, Math.abs(i - j));
return result;
}
How do I solve this problem?
At least, you could change the indices for looping and omit self checking and to check the same pairs again.
function solution(arr){
let result = 0
for (let i = 0; i < arr.length - 1; i++)
for (let j = i; j < arr.length; j++)
if (arr[i] === arr[j])
result = Math.max(result, Math.abs(i - j));
return result;
}
The shortest approach is O(n) by taking an hash table for storing the first found index for a value.
function solution(array) {
var hash = {};
return array.reduce(
(m, v, i) => Math.max(m, i - (hash[v] = v in hash ? hash[v] : i)),
0
);
}
var array = [1, 3, 4, 5, 1, 3, 4, 5, 6, 2, 3];
console.log(solution(array));
In the above function, the goal is to find the maximum number from array. Now the meaning of third to last line which is result = Math.max(result, Math.abs(i - j)); , I will break it into two parts to explain here,
First of all, Math.abs(i-j) will be executed and provide the absolute value from the difference between i and j.
After this, the outer function Math.max() method will be called which will provide you the maximum value between result and absolute value obtained from first step. Now the maximum value will be store in result. This is how the function is working.
Now this statement is conditional based, which means it will only execute if arr[i]==arr[j].
I hope it cleared the work flow of this program.

how to iterate through nested array items separately

I have a three-dimensional array, for example:
var array = [[1,0][3,3][2,1][0,8]]
and I want to do something with the first item in each sub-array, but something else with the second item in each sub-array.
So, for example, I would like to find the sum of array[0][0], array[1][0], array[2][0] and so on for array.length. But, I would like a separate result for array[0][1], array[1][1], array[2][1], etc.
I'm still learning javascript (very slowly) and, if possible, I would like to be pointed in the right direction, rather than getting a ready-made solution. I've been looking for possible solutions, and I think I may need a nested for loop, but I'm not sure how to structure it to get all the values.
I've been trying something along the lines of:
for (var i = 0; i < array.length; i++) {
for (var j = 0; j < array.length; j++) {
return array[i][j];
}
}
but I don't understand what's happening well enough to manipulate the result.
If anyone could steer me in the right direction toward finding a solution, that'd be much appreciated.
Thanks in advance.
You might consider using .reduce - on each iteration, add the first array value to a property of the accumulator, and do whatever you need to with the second array value, assigning its result to another property of the accumulator. For example, let's say for the second items, you wanted to get their product:
const input = [[1,0],[3,3],[2,1],[0,8]];
const { sum, product } = input
.reduce(({ sum=0, product=1 }, [item0, item1]) => ({
sum: sum + item0,
product: product * item1
}), {});
console.log(sum, product);
In the above code, the accumulator is an object with two properties, sum (starts at 0) and product (starts at 1). Inside the reduce, an object is returned, with the new sum being the old sum plus the first item in the array, and with the new product being the old product multiplied by the second item in the array. (of course, the resulting product is 0 because in the first sub-array, the second item is 0)
Also note that arrays always need commas separating each array item - you need to fix your input array's syntax.
Of course, you can also for loops if you have to, but I think array methods are preferable because they're more functional, have better abstraction, and don't require manual iteration. The same code with a for loop would look like this:
const input = [[1,0],[3,3],[2,1],[0,8]];
let sum = 0;
let product = 1;
for (let i = 0; i < input.length; i++) {
const [item0, item1] = input[i];
sum += item0;
product *= item1;
}
console.log(sum, product);
You just need one for-loop since you just have one array with arrays inside where you know the indexes you want to proccess. So it would be something as follows:
let sum1 = 0;
let sum2 = 0;
for(let i = 0; i < array.length; i++) {
sum1 += array[i][0];
sum2 += array[i][1];
}
console.log('sum1: ', sum1);
console.log('sum2: ', sum2);
Firstly the array you have posted is a 2d array not a 3d array.
And the nested for loop you have posted is perfect for what you want.
Your first for statment is looping through the the frist deminsion of your array. the second is getting each index in the second array
var array = [[1,0],[3,3],[2,1],[0,8]]
for (var i = 0; i < array.length; i++) {
//This loop over these [1,0],[3,3],[2,1],[0,8]
//So i on the first loop is this object [1,0] so so on
for (var j = 0; j < array.length; j++) {
//This will loop over the i object
//First loop j will be 1
//Here is where you would do something with the index i,j.
//Right now you are just returning 1 on the first loop
return array[i][j];
}
}
I hope this help your understanding
Since you asked for help with pointing you in the right direction, I would suggest you start with simple console.logs to see what's happening (comments are inline):
var array = [[1, 0],[3, 3],[2, 1],[0, 8]];
var results = [0, 0]; // this array is to store the results of our computation
for (var i = 0; i < array.length; i++) { // for each subarray in array
console.log('examining subarray ', array[i]);
for (var j = 0; j < array[i].length; j++) { // for each element in subarray
if (j === 0) {
console.log('... do something with the first element of this array, which is: ' + array[i][j]);
results[j] += array[i][j]
} else if (j === 1) {
console.log('... do something with the second element of this array, which is: ' + array[i][j]);
// do some other computation and store it in results
}
}
}
console.log('Final results are ', results);
You made a mistake on the second line. You need to iterate through the nested array and then take the value from the main array.
const mainArray = [[1, 0], [3, 3], [2, 1], [0, 8]];
for (let i = 0; i < mainArray.length; i++) {
const nestedArray = mainArray[i]
for (let j = 0; j < nestedArray.length; j++) {
const value = mainArray[i][j]
switch(j) {
case 0:
console.log(`first item of array number ${i+1} has value: ${value}`)
break;
case 1:
console.log(`second item of array number ${i+1} has value: ${value}`)
break;
}
}
}
You can use a for...of loop along with destructuring like so:
for(let [a, b] of array) {
// a will be the first item from the subarrays: array[0][0], array[1][0], ...
// b will be the second: : array[0][1], array[1][1], ...
}
Demo:
let array = [[1, 0], [3, 3], [2, 1], [0, 8]];
for(let [a, b] of array) {
console.log("a: " + a);
console.log("b: " + b);
}
Using a debugger within your loop would be a good way to watch and understand each step of the loop
Using the forEach method would be a clearer approach to loop through the array and its children
const items = [[1, 0],[3, 3],[2, 1],[0, 8]]
let results = {}
items.forEach((item, index) => {
// debugger;
item.forEach((subItem, subIndex) => {
// debugger;
if (results[subIndex]) {
results[subIndex] = results[subIndex] + subItem
} else {
results[subIndex] = subItem
}
})
})
console.log(results) // { 0: 6, 1: 12 }
// *********EXPLANATION BELOW ************
const items = [[1, 0],[3, 3],[2, 1],[0, 8]]
// store results in its own key:value pair
const results = {}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
// forEach is a more readable way to loop through an array
items.forEach((item, index) => {
// use console.log(item, index) to see the values in each loop e.g first loop contains `item = [1,0]`
// you can also use a debugger here which would be the easiest way to understand the iteration
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger
// debugger;
// loop over item (e.g [1,0]) to get subItems and their index
item.forEach((subItem, subIndex) => {
// get the result from previous sums from `result`
// and add them to the current subItem values
// if there was no previous sum(i.e for first entry)
// use subItem as the first value.
if (results[subIndex]) {
results[subIndex] = results[subIndex] + subItem
} else {
results[subIndex] = subItem
}
// Below is a oneliner way to do line 16 to 20 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
// results[subIndex] = results[subIndex] ? results[subIndex] + subItem : subItem
})
})
console.log(results) // { 0: 6, 1: 12 } the results of `array[0][0],array[1][0]...` are in 0 and the result of `array[0][1], array[1][1]...` are in 1 and so on.
Obligatory one-liner to bake your noodle.
console.log([[1, 0], [3, 3], [2, 1], [0, 8]].reduce((p, c) => [p[0] += c[0], p[1] += c[1]]));

JavaScript - more efficient way to truncate an array

I have an int array sorted ascending and I would like to remove array items from the tail according to the specific boundary. What is a better way to truncate an array in my case? Consider next code snippets:
var a = [1, 2, 3, 4];
var length = a.length;
var boundary = 2;
var count = 0;
for (var i = length - 1; i >= 0; i--) {
if (a[i] > boundary) {
a[i] = null; // or delete a[i] ???
count++;
}
}
a.length -= count;
Or the same but using splice:
for (var i = length - 1; i >= 0; i--) {
if (a[i] > boundary) {
a.splice(i, 1);
}
}
a.length -= count;
Thats sufficient ;) (as length is not a simple property, but rather a getter/setter which truncates/adds elements (ref))
Alternatively use splice:
a.splice(-count, count);
In modern engines, or with a shim, you can use Array.prototype.findIndex:
var a = [1, 2, 3, 4];
var boundary = 2;
a.length = a.findIndex( x => x > boundary );
console.log( a );
Since you're array is sorted you can also just use Array.prototype.filter:
var a = [1, 2, 3, 4];
var boundary = 2;
a = a.filter( x => x <= boundary );
console.log( a );
which may be slightly (negligibly) slower if the array is huge, but has more support in older engines.
Don't delete array entries at the end of an array to truncate it. Deleting array entries removes them from the array by creating a sparse array: the length property of the array remains unchanged:
var a = [1,2,3,4];
console.log( "a.length %s", a.length);
delete a[3];
console.log( "a[3] after deletion: %s", a[3]);
console.log( "a.length after deletion %s", a.length);
console.log( "a[3] still exists: %s", a.hasOwnProperty("3"));
Similar considerations apply to setting array entries to null. They will no longer test as truthy in a conditional expression, but have not been removed. As before the length of the array will remain unchanged.
Setting the length of the an array to something shorter than its existing value will truncate it in place. There are many ways of finding the boundary position at which to truncate the array. I suggest choosing one that appears natural to you and works in target browsers. E.G. using forSome on a sorted array may not meet your requirements :)
var a = [1,2,3,4];
var boundary = 2;
a.some(
(c,i) => {
if( c > boundary)
{ a.length = i;
return true;
}
}
);
console.log( a)
If using splice, note that all entries from the boundary position to the end of array can be deleted in one call rather than deleting them one at a time:
var a = [1,2,3,4];
var boundary = 2;
for( var i = a.length-1; a[i]>boundary; --i) {} // linear search
a.splice(i+1);
console.log(a);

Reversing certain number of elements in an array javascript

I am working on a code where I need to reverse certain no of elements in an array and rest should remain same. For example is an array has values of 1,2,3,4,5,6 and I have to reverse 4 elements of it then output should be 4,3,2,1,5,6. I am using below code to achieve this but getting error, please suggest.
function reverseArray(n, a) {
var interimArray1 = [];
//var interimArray2=[];
//var finalArray=[];
for (var i < n; i >= 0; i--) {
interimArray1.push[a[i]];
}
for (var i = n; i < a.length; i++) {
interimArray1.push[a[i]];
}
for (var i = 0; i < interimArray1.length; i++) {
console.log(interimArray1[i]);
}
}
var arr = [1, 2, 3, 4, 5, 6];
var num = 4;
reverseArray(num, arr);
The error in your code is that you intend to call the push method on a[i] like so:
interimArray1.push(a[i]);
but instead you write:
interimArray1.push[a[i]];
You make that mistake twice. To give arguments to the push method, you must use round parenthesis ().
With that fixed, you will see that your code works perfectly.
You can use Array#slice, Array#splice as follow.
function partialReverse(arr, num, from = 0) {
var slicedArr = arr.slice(from, num + from);
arr.splice(from, num); // Remove `num` items from array
arr.splice(from, 0, ...slicedArr.reverse()); // Add `num` reversed items
return arr;
}
var arr = [1, 2, 3, 4, 5, 6];
console.log(partialReverse(arr, 4, 0)); // Reverse four items from `arr` starting from 0th index
console.log(partialReverse(arr, 4, 1)); // Reverse four items from `arr` starting from 1st index
Lots of hints but you seem to be missing them. ;-)
You need to assign an initial value to i, so:
for (var i = n; ... )
===========^
Also, you need to use () to call functions, not [], so:
interimArray1.push(a[i]);
==================^====^
Same in the following for block. Otherwise, the code works though it's more verbose than it needs to be.
This is working :
I'm sure there are faster ways of doing it. Also, it will only work for elements at the beginning of the array but you can adjust the function for what you want to achieve.
var reverseArray = function(arr,elementsToReverse) {
var tempArrayRev = [];
var tempArray = [];
for (var i=0;i<arr.length;i++) {
if (i < elementsToReverse) {
tempArrayRev[i] = arr[i];
} else {
tempArray.push(arr[i]);
}
}
return tempArrayRev.reverse().concat(tempArray);
}
var array = [1,2,3,4,5,6];
document.getElementById('arrayOutput').innerHTML += reverseArray(array,4);
<div id="arrayOutput">Array :<br></div>
This is the answer you can test it.
function reverseArray(n, a) {
var interimArray1 = [];
for (var i = 0; i < a.length; i++) {
interimArray1.push(a[i]);
}
for (var i = num; i >=0; i--) {
interimArray1[i-1] = a[n - i];
}
for (var i = 0; i < interimArray1.length; i++) {
console.log(interimArray1[i]);
}
}
var arr = [1, 2, 3, 4, 5, 6];
var num = 4;
reverseArray(num, arr);
You could use something like this.
function reverseArray(n, arrIn) {
// Splice splits the array in 2 starting at 0 index going n long
var arrOut = arrIn.splice(0,n);
// reverse is pretty straight forward
arrOut = arrOut.reverse();
// Concat joins the two together
return arrOut.concat(arrIn);
}

Categories