I can't pass this coding challenge: Code Challenge: https://www.codewars.com/kata/550f22f4d758534c1100025a/train/javascript
because my code is TOO SLOW. I'm not sure which part of my code is causing the problem. That's why I need help to optimize it.
function dirReduc(arr){
if (arr.length === 0 || arr.length === 1) return [];
let lengthTracker = arr.length;
for (let i = 0; i < arr.length; i ) {
if (lengthTracker > arr.length) {
lengthTracker = arr.length;
i = 0;
}
switch(arr[i]) {
case "NORTH":
arr[i-1] === "SOUTH"? arr.splice(i-1,2) :
arr[i 1] === "SOUTH"? arr.splice(i,2) : null
break;
case "SOUTH":
arr[i-1] === "NORTH"? arr.splice(i-1,2) :
arr[i 1] === "NORTH"? arr.splice(i,2) : null
break;
case "EAST":
arr[i-1] === "WEST"? arr.splice(i-1,2) :
arr[i 1] === "WEST"? arr.splice(i,2) : null
break;
case "WEST":
arr[i-1] === "EAST"? arr.splice(i-1,2) :
arr[i 1] === "EAST"? arr.splice(i,2) : null
break;
}
i===arr.length-1? i=0:null
}
return arr;
}
CodePudding user response:
Splicing can be expensive. We can form a recurrence that assumes the function has already correctly reduced the next part of the list:
function matches(a, b){
return (a == "NORTH" && b == "SOUTH") ||
(b == "NORTH" && a == "SOUTH") ||
(a == "EAST" && b == "WEST") ||
(b == "EAST" && a == "WEST");
}
function f(A, i=0){
if (i == A.length)
return [];
const rest = f(A, i 1);
const [head,...tail] = rest;
if (head){
if (matches(A[i], head))
return tail;
else
return [A[i]].concat(rest);
}
return [A[i]];
}
CodePudding user response:
I see several problems with this. First, as I mentioned in the comments, splicing long arrays is costly and makes your algorithm O(n^2)
. Simple and faster would be to use a read-point and a write-point to copy the elements into itself one cell at a time, just skipping over the annihilations and then use splice once at the end to trim the uncopied cells of the end of the array. This would make it O(n)
.
Secondly, your code is looking both forward and backward for matches which is both unnecessary and can be confusing. Finally, there's no need for a switch (...)
as all of the branches do the same thing.
Here is how I would use your code to accomplish this, changing the things mentioned above and noted in the comments.
function dirReduc(arr){
if (arr.length === 0 || arr.length === 1) return [];
let lengthTracker = 0; // the write-point
for(let i = 0; i < arr.length; i ) { // i is the read-point
if(lengthTracker == 0) {
// if no output, copy readpoint and advance write-point
arr[lengthTracker] = arr[i];
lengthTracker ;
} else {
// replaces switch()
if (((arr[lengthTracker-1] === "NORTH") && (arr[i] === "SOUTH"))
|| ((arr[lengthTracker-1] === "SOUTH") && (arr[i] === "NORTH"))
|| ((arr[lengthTracker-1] === "EAST") && (arr[i] === "WEST"))
|| ((arr[lengthTracker-1] === "WEST") && (arr[i] === "EAST"))) {
lengthTracker--; // annihilate by decrementing the writepoint
} else {
// copy readpoint to after writepoint and advance
arr[lengthTracker ] = arr[i];
}
}
}
//trim the array to only include what was written
arr.splice(lengthTracker);
return arr;
}