Home >Web Front-end >JS Tutorial >Codewars - Pick peaks
Salutations.
I'm posting Codewars challenges and my thought process in this series. I'm using JS and Node 18 whenever possible. Just for the sake of clarity, I'm making fair use of them.
I took a break, and now I'm back. Did some challenges without posting the solution here though. Let's approach an easy challenge.
Pick peaks is a fun one. You need to find local maxima according to its mathematical definition. From GFG:
Mathematically, f (a) ≥ f (a -h) and f (a) ≥ f (a h) where h > 0, then a is called the Local maximum point.
In essence, we need to see which values are bigger than its closest neighbors. If a neighbor is missing we can't verify if it's a local maximum or not. So we won't check the borders of the array.
The following solution is not optimized. It should be one pass. Besides, I was taught to avoid using break and continue. But it does the job.
First we set the rules:
Second, it needs an specific return value: {pos:[], peaks:[]}
This challenge asks for position and value of the maxima.
Third, we need to set a loop for the array:
for (let i = 1 ; i < arr.length -1 ; i )
We skip the first and last value because they'll never be maxima according to the definition.
Fourth, we implement the rules:
for (let i = 1 ; i < arr.length -1 ; i++){ if (arr[i] <= arr[i-1]){ continue; } if (arr[i] > arr[i+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); } if (arr[i] == arr[i+1]){ // TO DO } } </p> <p>We'll need to refine that last part. That's the special treatment mentioned above while setting the rules. It is merely another loop that acts as a sub process:<br> </p> <pre class="brush:php;toolbar:false"> if (arr[i] == arr[i+1]){ for (let j=i +1 ; j< arr.length - 1; j++){ if (arr[j] == arr[j+1]){ continue; } if (arr[j] < arr[j+1]){ break; } if (arr[j] > arr[j+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); } } }
The sum of it all is this:
function pickPeaks(arr){ let cache = {pos:[], peaks:[]}; if (arr == false) { return cache; } for (let i = 1 ; i < arr.length -1 ; i++){ if (arr[i] <= arr[i-1]){ continue; } if (arr[i] > arr[i+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); } if (arr[i] == arr[i+1]){ for (let j=i +1 ; j< arr.length - 1; j++){ if (arr[j] == arr[j+1]){ continue; } if (arr[j] < arr[j+1]){ break; } if (arr[j] > arr[j+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); } } } } return cache; }
And now let's test it... Yay! It passed! Let's submit and...
Oh no. What???
This particular test: pickPeaks([1,2,5,4,3,2,3,6,4,1,2,3,3,4,5,3,2,1,2,3,5,5,4,3])
This should return: {pos:[2,7,14,20], peaks:[5,6,5,5]}
It returns: {pos:[2,7,14,20,20], peaks:[5,6,5,5,5]}
But why? The logic is sound. And every loop is correctly... Uhmmm... Wait... It gets duplicated. Position 20, value 5. It's there twice. There's got be something wrong here:
for (let i = 1 ; i < arr.length -1 ; i++){ if (arr[i] <= arr[i-1]){ continue; } if (arr[i] > arr[i+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); } if (arr[i] == arr[i+1]){ // TO DO } }
After some debugging with Dev Tools, I found it. Here's the problem:
if (arr[i] == arr[i+1]){ for (let j=i +1 ; j< arr.length - 1; j++){ if (arr[j] == arr[j+1]){ continue; } if (arr[j] < arr[j+1]){ break; } if (arr[j] > arr[j+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); } } }
It's missing a break statement. [...3,5,5,4,3] duplicates the second value because it only breaks out of the inner loop when it finds a sequence where this exit condition occurs:
function pickPeaks(arr){ let cache = {pos:[], peaks:[]}; if (arr == false) { return cache; } for (let i = 1 ; i < arr.length -1 ; i++){ if (arr[i] <= arr[i-1]){ continue; } if (arr[i] > arr[i+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); } if (arr[i] == arr[i+1]){ for (let j=i +1 ; j< arr.length - 1; j++){ if (arr[j] == arr[j+1]){ continue; } if (arr[j] < arr[j+1]){ break; } if (arr[j] > arr[j+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); } } } } return cache; }
Otherwise it keeps going. Turns out it should exit when it finds a maximum too:
if (arr[i] == arr[i+1]){ for (let j=i +1 ; j< arr.length - 1; j++){ if (arr[j] == arr[j+1]){ continue; } if (arr[j] < arr[j+1]){ break; } if (arr[j] > arr[j+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); } } }
FIXED:
if (arr[j] > arr[j+1]){ cache.pos.push(i); cache.peaks.push(arr[i]); }
Inefficient, but effective.
Take care. Drink water ???.
Previous
The above is the detailed content of Codewars - Pick peaks. For more information, please follow other related articles on the PHP Chinese website!