mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-06-16 21:06:35 +08:00
feat(curriculum): add binary search workshop (#60727)
Co-authored-by: Jessica Wilkins <67210629+jdwilkin4@users.noreply.github.com> Co-authored-by: Dario-DC <105294544+Dario-DC@users.noreply.github.com>
This commit is contained in:
parent
883286c242
commit
b5f2115a79
@ -4249,8 +4249,11 @@
|
||||
]
|
||||
},
|
||||
"workshop-binary-search": {
|
||||
"title": "Build a Binary Search",
|
||||
"intro": [""]
|
||||
"title": "Implement the Binary Search Algorithm",
|
||||
"intro": [
|
||||
"The binary search algorithm is a searching algorithm used to find a target item in a sorted list.",
|
||||
"In this workshop, you'll implement the binary search algorithm and return the path it took to find the target or return 'Value not found'."
|
||||
]
|
||||
},
|
||||
"lab-bisection-method": {
|
||||
"title": "Build a Bisection Method",
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Introduction to the Implement the Binary Search Algorithm
|
||||
block: workshop-binary-search
|
||||
superBlock: full-stack-developer
|
||||
---
|
||||
|
||||
## Introduction to the Build a Binary Search
|
||||
|
||||
This is workshop will cover how to implement the binary search algorithm in Python.
|
||||
77
curriculum/challenges/_meta/workshop-binary-search/meta.json
Normal file
77
curriculum/challenges/_meta/workshop-binary-search/meta.json
Normal file
@ -0,0 +1,77 @@
|
||||
{
|
||||
"name": "Implement the Binary Search Algorithm",
|
||||
"isUpcomingChange": true,
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true,
|
||||
"dashedName": "workshop-binary-search",
|
||||
"superBlock": "full-stack-developer",
|
||||
"blockLayout": "challenge-grid",
|
||||
"blockType": "workshop",
|
||||
"challengeOrder": [
|
||||
{
|
||||
"id": "683ec39565dbc7e3375263b1",
|
||||
"title": "Step 1"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff7a",
|
||||
"title": "Step 2"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff7b",
|
||||
"title": "Step 3"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff7c",
|
||||
"title": "Step 4"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff7d",
|
||||
"title": "Step 5"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff7e",
|
||||
"title": "Step 6"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff7f",
|
||||
"title": "Step 7"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff80",
|
||||
"title": "Step 8"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff81",
|
||||
"title": "Step 9"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff82",
|
||||
"title": "Step 10"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff83",
|
||||
"title": "Step 11"
|
||||
},
|
||||
{
|
||||
"id": "683ec95f2f8781355556ff84",
|
||||
"title": "Step 12"
|
||||
},
|
||||
{
|
||||
"id": "684165a72e33e26a40904f8b",
|
||||
"title": "Step 13"
|
||||
},
|
||||
{
|
||||
"id": "684169b00a073c9b9f0a703c",
|
||||
"title": "Step 14"
|
||||
},
|
||||
{
|
||||
"id": "68416aab85dd00a7852cdeb6",
|
||||
"title": "Step 15"
|
||||
},
|
||||
{
|
||||
"id": "68416d66013635cb6325eb6d",
|
||||
"title": "Step 16"
|
||||
}
|
||||
],
|
||||
"helpCategory": "Python"
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
---
|
||||
id: 683ec39565dbc7e3375263b1
|
||||
title: Step 1
|
||||
challengeType: 20
|
||||
dashedName: step-1
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In a previous lecture, you learned about binary search and how it differs from linear search.
|
||||
|
||||
In this workshop, you will put that into practice by building a binary search algorithm.
|
||||
|
||||
To begin, create a `binary_search` function with a `search_list` and `value` parameters.
|
||||
|
||||
`search_list` is the list of elements the function will search within, and `value` is the target the function will try to find within the `search_list`.
|
||||
|
||||
Add the `pass` keyword inside the function for now so the test can pass.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `binary_search` function.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`_Node(_code).has_function("binary_search")`))
|
||||
})
|
||||
```
|
||||
|
||||
Your `binary_search` function should have a `search_list` and `value` parameters.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").has_args("search_list, value") or _Node(_code).find_function("binary_search").has_args("value, search_list")`
|
||||
)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,38 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff7a
|
||||
title: Step 2
|
||||
challengeType: 20
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The binary search algorithm you're building will not just return `True` or `False` to indicate whether the value was found or not. It will also return the path it takes to find that value. And for that, you will have a `path_to_target` variable to track the path.
|
||||
|
||||
Inside your `binary_search` function, replace the `pass` keyword with a `path_to_target` variable and initialize it to an empty list, for a start.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `path_to_target` variable set to an empty list within your `binary_search` function. Don't forget to remove the `pass` keyword.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () =>
|
||||
assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").find_body().is_equivalent("path_to_target = []") and not _Node(_code).find_function("binary_search").has_pass()`
|
||||
)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
def binary_search(search_list, value):
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,68 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff7b
|
||||
title: Step 3
|
||||
challengeType: 20
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In binary search, there is the lowest possible index and the highest possible index.
|
||||
|
||||
The lowest possible index represents the leftmost boundary in the current portion of the values being searched within, in this case, `search_list`. The highest possible index, on the other hand, represents the rightmost boundary in the values being searched.
|
||||
|
||||
To account for those two, you have to consider the entire list being searched. So, inside the `binary_search` function, define a `low` variable with a value of `0`, and a `high` variable with a value that accounts for the last index in the list being searched.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable named `low` in your `binary_search` function.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`_Node(_code).find_function("binary_search").has_variable("low")`))
|
||||
})
|
||||
```
|
||||
|
||||
Your `low` variable should be set to `0`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () =>
|
||||
assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").find_variable("low").is_equivalent("low = 0")`
|
||||
)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
You should have a variable named `high` in your `binary_search` function.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`_Node(_code).find_function("binary_search").has_variable("high")`))
|
||||
})
|
||||
```
|
||||
|
||||
Your `high` variable should be set to `len(search_list) - 1`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").find_variable("high").is_equivalent("high = len(search_list) - 1")`
|
||||
))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,43 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff7c
|
||||
title: Step 4
|
||||
challengeType: 20
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that you've defined the boundaries of your search, it's time to create the loop that will perform the binary search algorithm.
|
||||
|
||||
Binary search works by repeatedly narrowing down the search space. This process continues as long as there is a valid range of elements to check.
|
||||
|
||||
You can express this with a `while` loop that will continue as long as your `low` pointer is less than or equal to your `high` pointer.
|
||||
|
||||
If `low` ever becomes greater than `high`, it means the search space has become empty, and the `value` is not in the list.
|
||||
|
||||
Inside the `binary_search` function, create a `while` loop with a condition that checks if `low` is less than or equal to high. Inside the loop, add the `pass` keyword as a placeholder for now.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `while` loop that runs while `low` is less than or equal to `high`.
|
||||
|
||||
```js
|
||||
({ test: () => runPython(`
|
||||
_cond = _Node(_code).find_function("binary_search").find_whiles()[0].find_conditions()[0]
|
||||
assert _cond.is_equivalent("low <= high") or _cond.is_equivalent("high >= low")`
|
||||
) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,43 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff7d
|
||||
title: Step 5
|
||||
challengeType: 20
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
To get started with the loop, you need to find the middle index of the current search space.
|
||||
|
||||
You can get the middle index by calculating the average of the `low` and `high` variables. You will have to use floor division to get the average after adding the two values, so the answer would always be an integer rounded down, as the indices must be integers.
|
||||
|
||||
Remove the `pass` keyword from your `while` loop and create a `mid` variable set to the average of `low` and `high`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove the `pass` keyword from the while loop and create a `mid` variable set to `(low + high) // 2`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: ()=>
|
||||
assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").find_whiles()[0].find_body().is_equivalent("mid = (low + high) // 2") or _Node(_code).find_function("binary_search").find_whiles()[0].find_body().is_equivalent("mid = (high + low) // 2")`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
--fcc-editable-region--
|
||||
while low <= high:
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,43 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff7e
|
||||
title: Step 6
|
||||
challengeType: 20
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that you've calculated the `mid` index, you need to actually retrieve the value from the `search_list` at that index. This value is what you will compare against your `value` parameter, which is the target you are searching for.
|
||||
|
||||
Create a `value_at_middle` variable and assign it the element from `search_list` that is located at the `mid` index.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `value_at_middle` variable set to `search_list[mid]`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () =>
|
||||
assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").find_whiles()[0].find_body().is_equivalent("mid = (low + high) // 2 \\nvalue_at_middle = search_list[mid]")`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
--fcc-editable-region--
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,41 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff7f
|
||||
title: Step 7
|
||||
challengeType: 20
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, include `value_at_middle` in the `path_to_target` list to track the steps taken during the search, regardless of whether it's the target.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `append()` method to add `value_at_middle` to the `path_to_target` list.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () =>
|
||||
assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").find_whiles()[0].find_body().is_equivalent("mid = (low + high) // 2 \\nvalue_at_middle = search_list[mid] \\npath_to_target.append(value_at_middle)")`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
--fcc-editable-region--
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,55 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff80
|
||||
title: Step 8
|
||||
challengeType: 20
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The next thing to do is to create a condition that will check if the target `value` is in the middle.
|
||||
|
||||
Inside the `while` loop, create an `if` statement that checks if the target `value` is equal to `value_at_middle`. If it is, return the `path_to_target` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create an `if` statement that checks if the `value` is equal to `value_at_middle`.
|
||||
|
||||
```js
|
||||
({ test: () => runPython(`
|
||||
_cond = _Node(_code).find_function("binary_search").find_whiles()[0].find_body().find_ifs()[0].find_conditions()[0]
|
||||
assert _cond.is_equivalent("value == value_at_middle") or _cond.is_equivalent("value_at_middle == value")
|
||||
`) })
|
||||
```
|
||||
|
||||
You should return the `path_to_target` variable inside the `if` statement.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () =>
|
||||
assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").find_whiles()[0].find_body().find_ifs()[0].find_body().is_equivalent("return path_to_target")`
|
||||
)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,61 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff81
|
||||
title: Step 9
|
||||
challengeType: 20
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to test out things so you will understand the flow of the algorithm at this initial stage.
|
||||
|
||||
To do that, you need to first break out of the loop. That's because the current implementation will only allow one iteration, so if the condition is not met, there will be an infinite loop.
|
||||
|
||||
Just after the `if`statement, use the `break` keyword to break out of the `while` loop. Then, after the `while` loop, return an empty list to signify that the value was not found.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `break` keyword to break out of the `while` loop after the `if` statement.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(
|
||||
`_Node(_code).find_function("binary_search").find_whiles()[0].find_body().has_stmt("break")`)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
You should return an empty list after your `while` loop.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () =>
|
||||
assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").has_return("[]")`
|
||||
)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
|
||||
--fcc-editable-region--
|
||||
if value == value_at_middle:
|
||||
return path_to_target
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,59 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff82
|
||||
title: Step 10
|
||||
challengeType: 20
|
||||
dashedName: step-10
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Be reminded that the function takes a list called `search_list` and the `value` you're looking for.
|
||||
|
||||
Now, call the function with `binary_search([1, 2, 3, 4, 5], 3)` and `binary_search([1, 2, 3, 4, 5, 9], 4)` and print the calls right away.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call the function with `binary_search([1, 2, 3, 4, 5], 3)` and print it right away.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_call("print(binary_search([1, 2, 3, 4, 5], 3))")
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should call the function with `binary_search([1, 2, 3, 4, 5, 9], 4)` and print it right away.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_call("print(binary_search([1, 2, 3, 4, 5, 9], 4))")
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
|
||||
if value == value_at_middle:
|
||||
return path_to_target
|
||||
break
|
||||
return []
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,52 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff83
|
||||
title: Step 11
|
||||
challengeType: 20
|
||||
dashedName: step-11
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You can see that the first call returns `[3]`. That's because `3` is the middle value in `[1, 2, 3, 4, 5]`.
|
||||
|
||||
On the other hand, the second call returns an empty list. This happens because, after checking the middle value, the loop currently lacks the logic to narrow the search range by updating the `low` or `high` variables. It only acts as a single midpoint check and then finishes without further searching.
|
||||
|
||||
To allow the binary search to continue narrowing its search, add an `elif` block that checks if `value` is greater than `value_at_middle`. Add the `pass` keyword inside the `elif` for now.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add an `elif` block for when `value` is greater than `value_at_middle`.
|
||||
|
||||
```js
|
||||
({ test: () => runPython(`
|
||||
_cond = _Node(_code).find_function("binary_search").find_whiles()[0].find_ifs()[0].find_conditions()[1]
|
||||
assert _cond.is_equivalent("value > value_at_middle") or _cond.is_equivalent("value_at_middle < value")
|
||||
`) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
|
||||
--fcc-editable-region--
|
||||
if value == value_at_middle:
|
||||
return path_to_target
|
||||
|
||||
--fcc-editable-region--
|
||||
break
|
||||
return []
|
||||
|
||||
print(binary_search([1, 2, 3, 4, 5], 3))
|
||||
print(binary_search([1, 2, 3, 4, 5, 9], 4))
|
||||
```
|
||||
@ -0,0 +1,51 @@
|
||||
---
|
||||
id: 683ec95f2f8781355556ff84
|
||||
title: Step 12
|
||||
challengeType: 20
|
||||
dashedName: step-12
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
If the condition in the `elif` is true, then remove the `pass` keyword and update the value of the `low` variable by adding `1` to the `mid` variable.
|
||||
|
||||
This will extend the search to the right half of the current search areas in the list, because if the `value` is greater than `value_at_middle`, it means the `value` must be in the right half of the current search area.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove the `pass` keyword and update the `low` variable to `mid + 1`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(
|
||||
runPython(`_Node(_code).find_function("binary_search").find_whiles()[0].find_ifs()[0].find_bodies()[1].is_equivalent("low = mid + 1")`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
|
||||
if value == value_at_middle:
|
||||
return path_to_target
|
||||
--fcc-editable-region--
|
||||
elif value > value_at_middle:
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
break
|
||||
return []
|
||||
|
||||
print(binary_search([1, 2, 3, 4, 5], 3))
|
||||
print(binary_search([1, 2, 3, 4, 5, 9], 4))
|
||||
```
|
||||
@ -0,0 +1,50 @@
|
||||
---
|
||||
id: 684165a72e33e26a40904f8b
|
||||
title: Step 13
|
||||
challengeType: 20
|
||||
dashedName: step-13
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, if the `value` is not found at the middle and is also not greater than `value_at_middle`, then the `value` must be less than `value_at_middle`, and must be on the left. The `else` block will handle this.
|
||||
|
||||
So, finish up the loop by removing the `break` keyword and adding an `else` block. Inside it, update the `high` variable by subtracting `1` from `mid`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should replace the `break` keyword with an else block that updates the `high` variable to `mid - 1`.
|
||||
|
||||
```js
|
||||
({ test: () => runPython(`
|
||||
_Node(_code).find_function("binary_search").find_whiles()[0].find_ifs()[0].find_bodies()[2].is_equivalent("high = mid - 1")
|
||||
`) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
|
||||
if value == value_at_middle:
|
||||
return path_to_target
|
||||
elif value > value_at_middle:
|
||||
low = mid + 1
|
||||
--fcc-editable-region--
|
||||
break
|
||||
--fcc-editable-region--
|
||||
return []
|
||||
|
||||
print(binary_search([1, 2, 3, 4, 5], 3))
|
||||
print(binary_search([1, 2, 3, 4, 5, 9], 4))
|
||||
```
|
||||
@ -0,0 +1,58 @@
|
||||
---
|
||||
id: 684169b00a073c9b9f0a703c
|
||||
title: Step 14
|
||||
challengeType: 20
|
||||
dashedName: step-14
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Did you notice the second function call now has the values `3, 5, 4` in the list? That indicates the binary search is working as intended.
|
||||
|
||||
This is how it happened: The algorithm first checked `3` as the middle of the initial list. Since `4` is greater than `3`, the search shifted to the right half. It then examined `5` as the new middle. Because `4` is less than `5`, the search moved to the left, ultimately identifying `4` as the middle of the final range.
|
||||
|
||||
To test the function again, call it with `[1, 3, 5, 9, 14, 22], 10` and print the call right away. This is a situation in which the value will not be found.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call the function with `binary_search([1, 3, 5, 9, 14, 22], 10)` and print it right away.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(
|
||||
`_Node(_code).has_call("print(binary_search([1, 3, 5, 9, 14, 22], 10))")`
|
||||
)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
|
||||
if value == value_at_middle:
|
||||
return path_to_target
|
||||
elif value > value_at_middle:
|
||||
low = mid + 1
|
||||
else:
|
||||
high = mid - 1
|
||||
|
||||
return []
|
||||
|
||||
print(binary_search([1, 2, 3, 4, 5], 3))
|
||||
print(binary_search([1, 2, 3, 4, 5, 9], 4))
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@ -0,0 +1,56 @@
|
||||
---
|
||||
id: 68416aab85dd00a7852cdeb6
|
||||
title: Step 15
|
||||
challengeType: 20
|
||||
dashedName: step-15
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You can see that the last call prints an empty list. To further specify that the value is not in the searched list, update the `return` statement and return an empty list and the message `Value not found`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should update the `return` statement to return `[], 'Value not found'`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () =>
|
||||
assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").has_return("[], 'Value not found'")`
|
||||
)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
|
||||
if value == value_at_middle:
|
||||
return path_to_target
|
||||
elif value > value_at_middle:
|
||||
low = mid + 1
|
||||
else:
|
||||
high = mid - 1
|
||||
|
||||
--fcc-editable-region--
|
||||
return []
|
||||
--fcc-editable-region--
|
||||
|
||||
print(binary_search([1, 2, 3, 4, 5], 3))
|
||||
print(binary_search([1, 2, 3, 4, 5, 9], 4))
|
||||
print(binary_search([1, 3, 5, 9, 14, 22], 10))
|
||||
```
|
||||
@ -0,0 +1,86 @@
|
||||
---
|
||||
id: 68416d66013635cb6325eb6d
|
||||
title: Step 16
|
||||
challengeType: 20
|
||||
dashedName: step-16
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
One final small enhancement you can add is to also show the index at which the target `value` is found.
|
||||
|
||||
So, instead of returning only `path_to_target` in the `if` statement, add an `f-string` with the message `Value found at index {mid}`.
|
||||
|
||||
With that, your binary search algorithm workshop is complete!
|
||||
|
||||
# --hints--
|
||||
|
||||
You should return `path_to_target, f'Value found at index {mid}'` inside the `if` block.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () =>
|
||||
assert(
|
||||
runPython(
|
||||
`_Node(_code).find_function("binary_search").find_whiles()[0].find_body().find_ifs()[0].find_body().is_equivalent("return path_to_target, f'Value found at index {mid}'")`
|
||||
)
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
|
||||
if value == value_at_middle:
|
||||
--fcc-editable-region--
|
||||
return path_to_target
|
||||
--fcc-editable-region--
|
||||
elif value > value_at_middle:
|
||||
low = mid + 1
|
||||
else:
|
||||
high = mid - 1
|
||||
|
||||
return [], "Value not found"
|
||||
|
||||
print(binary_search([1, 2, 3, 4, 5], 3))
|
||||
print(binary_search([1, 2, 3, 4, 5, 9], 4))
|
||||
print(binary_search([1, 3, 5, 9, 14, 22], 10))
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```py
|
||||
def binary_search(search_list, value):
|
||||
path_to_target = []
|
||||
low = 0
|
||||
high = len(search_list) - 1
|
||||
|
||||
while low <= high:
|
||||
mid = (low + high) // 2
|
||||
value_at_middle = search_list[mid]
|
||||
path_to_target.append(value_at_middle)
|
||||
|
||||
if value == value_at_middle:
|
||||
return path_to_target, f"Value found at index {mid}"
|
||||
elif value > value_at_middle:
|
||||
low = mid + 1
|
||||
else:
|
||||
high = mid - 1
|
||||
|
||||
return [], "Value not found"
|
||||
|
||||
print(binary_search([1, 2, 3, 4, 5], 3))
|
||||
print(binary_search([1, 2, 3, 4, 5, 9], 4))
|
||||
print(binary_search([1, 3, 5, 9, 14, 22], 10))
|
||||
```
|
||||
Loading…
Reference in New Issue
Block a user