Problem overview
The function canJump receives a slice of hurdle heights, hurdleHeights, and the height the jumper can clear, jumperHeight. It returns true if the jumper can clear every hurdle and false if any hurdle is too tall. A hurdle is cleared when the jump height is greater than or equal to the hurdle height, so a hurdle exactly as tall as the jump is fine.
With hurdles [1, 2, 3, 4, 5] and a jump of 5, every hurdle is at most 5, so the answer is true. With hurdles [1, 2, 1] and a jump of 1, the middle hurdle is 2, which is higher than 1, so the answer is false. With no hurdles at all, the answer is true, because there is nothing to fail.
Approach: one hurdle that is too tall is enough
The jumper has to clear all hurdles, so a single failure settles the answer. Check the hurdles one by one. As soon as one is higher than jumperHeight, return false. If the loop finishes without finding such a hurdle, every one was clearable, so return true.
This is the mirror image of searching for a value: there, one match means true; here, one violation means false. In both, the answer you can only give after looking at everything goes after the loop.
Step by step
- Loop over the hurdles with
range, calling each oneheight. The index is not needed, so it goes to the blank identifier_. - Test for a failure. If
heightis strictly greater thanjumperHeight, the jumper can't clear it, and the function returnsfalseright away. The comparison is strict because a hurdle of equal height is still cleared. - Return
trueafter the loop. Reaching this line means no hurdle failed the test. An empty slice skips the loop and arrives here directly, which is the required answer for zero hurdles.
The solution in Go
func canJump(hurdleHeights []int, jumperHeight int) bool {
for _, height := range hurdleHeights {
if height > jumperHeight {
return false
}
}
return true
}
Some Go details to note:
- Slices, not fixed arrays. The parameter type
[]intis a slice, which can have any length. The examples in this lesson are written as slice literals such as[]int{1, 2, 3, 4, 5}. - The blank identifier.
rangealways produces an index and a value for a slice. Go refuses to compile unused variables, so the index is discarded with_. - Early return. A
returninside a loop leaves the whole function, so the remaining hurdles are skipped. - Empty and
nilslices. Ranging over anilslice is legal and runs the body zero times, socanJump(nil, 0)returnstrue.
Complexity
Time: O(n) for n hurdles. In the worst case, every hurdle is checked once. If an early hurdle is too tall, the function stops sooner.
Space: O(1). Only the loop variables are used, and the slice is not copied.
Edge cases and common mistakes
- Equal heights.
canJump([]int{3, 3}, 3)istrue. Writingheight >= jumperHeightin the check would wrongly reject it. - Empty slice.
canJump([]int{}, 1)istrue. A version that returns the result of the first comparison would fail here, since there is no first hurdle. - Returning true too early. Writing
else { return true }inside the loop makes the first small hurdle decide the whole answer.[]int{1, 2, 1}with a jump of 1 would givetrueinstead offalse. - Comparing the wrong way round. The failure test is hurdle above jump,
height > jumperHeight. Reversing the operands tests the opposite condition. - Using the name from the examples. The function in this lesson is
canJump, so call it by that name.
Testing
canJump([]int{1, 2, 3, 4, 5}, 5)givestrue.canJump([]int{5, 5, 3, 4, 5}, 3)givesfalse.canJump([]int{5, 4, 5, 6}, 10)givestrue.canJump([]int{1, 2, 1}, 1)givesfalse.canJump([]int{}, 0)givestrue.