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> <div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><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!