├── .gitignore ├── README.md ├── Short-Answer ├── Algorithms_Answers.md └── Algorithms_Questions.md ├── recursive_count_th ├── count_th.py └── test_count_th.py └── robot_sort ├── robot_sort.py └── test_robot.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.pyc 4 | .vscode/ 5 | __pycache__ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sprint Challenge: Algorithms 2 | 3 | In this week's Sprint you explored and implemented some classic algorithmic approaches and used them to solve novel problems. You also implemented some classic and fundamental sorting algorithms and learned how to go about evaluating their respective runtimes and performance. This Sprint Challenge aims to assess your comfort with these topics through exercises that build on the algorithmic intuition you've started to build up. 4 | 5 | ## Instructions 6 | 7 | **Read these instructions carefully. Understand exactly what is expected _before_ starting this Sprint Challenge.** 8 | 9 | This is an individual assessment. All work must be your own. Your Challenge score is a measure of your ability to work independently using the material covered throughout this sprint. You need to demonstrate proficiency in the 10 | concepts and objectives that were introduced and that you practiced in the preceding days. 11 | 12 | You are not allowed to collaborate during the Sprint Challenge. However, you are encouraged to follow the twenty-minute rule and seek support from your TL and 13 | Instructor in your cohort help channel on Slack. Your submitted work reflects your proficiency in the concepts and topics that were covered this sprint. 14 | 15 | You have three hours to complete this Sprint Challenge. Plan your time accordingly. 16 | 17 | ## Commits 18 | 19 | Commit your code regularly and meaningfully. This helps both you (in case you ever need to return to old code for any number of reasons) and it also helps your team lead to more thoroughly assess your work. 20 | 21 | ## Description 22 | 23 | This Sprint Challenge is split into two separate parts that test your ability to analyze and write algorithms. 24 | 25 | ### Short Answer Questions 26 | 27 | > It is recommended that you spend no more than 1 hour on this portion of the Sprint Challenge. 28 | 29 | For this portion of the Sprint Challenge, you'll be answering questions posed in the `Algorithms_Questions.md` document inside the `Short-Answer` directory. Write down your answer and also write down a justification for _why_ you put down that answer. This could net you some partial credit if your justification is sound but the answer you put down turns out to not be correct. Add your answers to the questions in the `Algorithms_Answers.md` file. 30 | 31 | #### 1. Analyzing runtime _(3 points)_ 32 | 33 | Given 3 blocks of code, identify the runtime of each. Justify your answer. 34 | 35 | #### 2. Find the highest floor _(3 points)_ 36 | 37 | Suppose that you have an n-story building and plenty of eggs. Suppose also that an egg gets broken if it is thrown off floor f or higher, and doesn't get broken if dropped off a floor less than floor f. Devise a strategy to determine the value of f such that the number of dropped + broken eggs is minimized. 38 | 39 | Write out your proposed algorithm in plain English or pseudocode AND give the runtime complexity of your solution. 40 | 41 | ### Code Challenges 42 | 43 | #### 3. Use recursion to complete the `count_th()` function _(3 points)_ 44 | Inside the `recursive_count_th` directory you'll find the `count_th.py` file. In this file, please add your recursive implementation to the `count_th()` method following these rules: 45 | 46 | * Your function should take in a signle parameter (a string `word`) 47 | * Your function should return a count of how many occurences of ***"th"*** occur within `word`. Case matters. 48 | * Your function must utilize recursion. 49 | * It cannot contain any loops. 50 | 51 | Run `python test_count_th.py` to run the tests for your `count_th()` function to ensure that your implementation is correct. 52 | 53 | 54 | #### 4. Understand, plan, & implement the Robot Sort algorithm _(6 points)_ 55 | 56 | You have been given a robot with very basic capabilities: 57 | 58 | * It can move left or right. 59 | * It can pick up an item 60 | * If it tries to pick up an item while already holding one, it will swap the items instead. 61 | * It can compare the item it's holding to the item in front of it. 62 | * It can switch a light on its head on or off. 63 | 64 | Your task is to program this robot to sort lists using ONLY these abilities. 65 | 66 | ##### Rules 67 | 68 | Inside the `robot_sort` directory you'll find the `robot_sort.py` file. Open it up and read through each of the robot's abilities. Once you've understood those, start filling out the `sort()` method following these rules: 69 | 70 | * You may use any pre-defined robot methods. 71 | * You may NOT modify any pre-defined robot methods. 72 | * You may use logical operators. (`if`, `and`, `or`, `not`, etc.) 73 | * You may use comparison operators. (`>`, `>=`, `<`, `<=`, `==`, `is`, etc.) 74 | * You may use iterators. (`while`, `for`, `break`, `continue`) 75 | * You may NOT store any variables. (`=`) 76 | * You may NOT access any instance variables directly. (`self._anything`) 77 | * You may NOT use any Python libraries or class methods. (`sorted()`, etc.) 78 | * You may define robot helper methods, as long as they follow all the rules. 79 | 80 | ##### Hints 81 | 82 | * Make sure you understand the problem and all of the rules! A solution that breaks the rules will not receive full credit. 83 | 84 | * If you're unsure if an operator or method is allowed, ask. 85 | 86 | * Lay out some numbered cards in a line and try sorting them as if you were the robot. 87 | 88 | * Come up with a plan and write out your algorithm before coding. If your plan is sound but you don't reach a working implementation in three hours, you may receive partial credit. 89 | 90 | * There is no efficiency requirement but you may lose points for an unreasonably slow solution. Tests should run in far less than 1 second. 91 | 92 | * We discussed a sorting method this week that might be useful. Which one? 93 | 94 | * The robot has exactly one bit of memory: its light. Why is this important? 95 | 96 | Run `python test_robot.py` to run the tests for your `robot_sort()` function to ensure that your implementation is correct. 97 | 98 | ### Stretch 99 | 100 | Uncomment the `test_stretch_times()` test in `test_robot.py`. Can you optimize your robot sort to perform better than the given times? 101 | 102 | ## Rubric 103 | | OBJECTIVE | TASK | 1 - DOES NOT MEET Expectations | 2 - MEETS Expectations | 3 - EXCEEDS Expectations | SCORE | 104 | | ---------- | ----- | ------- | ------- | ------- | -- | 105 | | _Student should be able to define what runtime complexity is, differentiate between various classifications and categorize the performance of an algorithm using Big O notation_ | 1. Complete Analysis of Algorithms - Exercise I | Student correctly identifies 0-1/3 runtimes | Student correctly identifies 2/3 runtimes | Student correctly identifies 3/3 runtimes | | 106 | | _Student should be able to describe the differences between Linear and Binary Searching algorithms_ | 2. Complete Analysis of Algorithms - Exercise II | Student does NOT clearly identify a strategy that would allow us to search for and find floor `f`.

It is either incorrect **OR** requires the TL to make assumptions about how the strategy works. | Student's answer describes a searching strategy **BUT** either i) does NOT correctly identify the runtime **OR** ii) recommends an approach that will work but is not ideal in terms of efficiency | Student's answer describes a strategy that functions (like Binary Search) and is easy to understand (if their description is in English, all details are provided, if in psuedocode, variables names make sense, code is clean and easy to follow) **AND** performs better than (O(n)) **AND** identifies the runtime correctly. | | 107 | | _Student should be able to identify when a problem is amenable to a recursive solution and utilize recursion in order to solve it_ | 3. Utilize recursion to complete `count_th()` | Student's function does not compile & run **OR**

runs but does NOT pass a minimum of **4/5** of test cases. | Student's function passes **4/5** of test cases | Student's function passes **ALL** test cases | | 108 | | _Student should be able to demonstrate an understanding of the implementation of various iterative & recursive sorting algorithms_ | 4. Understand and plan an approach to implement the `robot_sort()` function | Student's comments, psuedocode, or solution will not sort a collection of elements because it is incomplete or contains 4 or more errors preventing it from executing as intended. | Student's comments, psuedocode, or solution has **MOST** of the elements needed for a robot to sort a given collection of items. May contain up to 3 minor errors.

Robot Sort rules violations will not be held against students in this row. | Student's comments, psuedocode, or solution has **ALL** of the elements needed for a robot to sort a given collection of items. Contains no errors or missing logic. Clear & easy to follow algorithm.

Robot Sort rules violations will not be held against students in this row. | | 109 | | _Student should be able to approach a novel problem and come up with a workable first-pass solution._ | 5. Implement the `robot_sort()` function | Student's function does not compile & run **OR**

runs but fails to pass a minimum of **4/5** of test cases. | Student's function follows **ALL** [rules](https://github.com/BloomInstituteOfTechnology/Sprint-Challenge--Algorithms#rules) **BUT** only passes **4/5** of test cases, takes longer than 1 second to run OR the student cannot clearly explain what some segments of the code are doing to the TL. | Student's function follows **ALL** [rules](https://github.com/BloomInstituteOfTechnology/Sprint-Challenge--Algorithms#rules), runs in less than 1 second **AND** passes **ALL** test cases. Code is well-formatted, includes appropriate comments, and student can walk-through their solution and explain their process clearly to the TL. | | 110 | | _Student should be able to apply techniques such as memoization or heuristics to improve an existing first-pass solution_ | [STRETCH] Optimize `robot_sort()` to improve runtime | Student's function passes ALL test cases **AND**
**1/4** stretch tests outperform the benchmark | Student's function passes ALL test cases **AND**
**2/4** stretch tests outperform the benchmark | Student's function passes ALL test cases **AND**
**4/4** stretch tests outperform the benchmark | | 111 | 112 | 113 | ### Passing the Sprint 114 | Score ranges for a 1, 2, and 3 are shown in the rubric above. For a student to have _passed_ a sprint challenge, they need to earn an **average of at least 2** for all items on the rubric. 115 | -------------------------------------------------------------------------------- /Short-Answer/Algorithms_Answers.md: -------------------------------------------------------------------------------- 1 | #### Please add your answers to the ***Analysis of Algorithms*** exercises here. 2 | 3 | ## Exercise I 4 | 5 | a) 6 | 7 | 8 | b) 9 | 10 | 11 | c) 12 | 13 | ## Exercise II 14 | 15 | 16 | -------------------------------------------------------------------------------- /Short-Answer/Algorithms_Questions.md: -------------------------------------------------------------------------------- 1 | # Analysis of Algorithms 2 | 3 | ## Exercise I 4 | 5 | Give an analysis of the running time of each snippet of 6 | pseudocode with respect to the input size n of each of the following: 7 | 8 | ```python 9 | a) a = 0 10 | while (a < n * n * n): 11 | a = a + n * n 12 | ``` 13 | 14 | 15 | ``` 16 | b) sum = 0 17 | for i in range(n): 18 | j = 1 19 | while j < n: 20 | j *= 2 21 | sum += 1 22 | ``` 23 | 24 | ``` 25 | c) def bunnyEars(bunnies): 26 | if bunnies == 0: 27 | return 0 28 | 29 | return 2 + bunnyEars(bunnies-1) 30 | ``` 31 | 32 | ## Exercise II 33 | 34 | Suppose that you have an n-story building and plenty of eggs. Suppose also that an egg gets broken if it is thrown off floor f or higher, and doesn't get broken if dropped off a floor less than floor f. Devise a strategy to determine the value of f such that the number of dropped + broken eggs is minimized. 35 | 36 | Write out your proposed algorithm in plain English or pseudocode AND give the runtime complexity of your solution. 37 | -------------------------------------------------------------------------------- /recursive_count_th/count_th.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Your function should take in a single parameter (a string `word`) 3 | Your function should return a count of how many occurences of ***"th"*** occur within `word`. Case matters. 4 | Your function must utilize recursion. It cannot contain any loops. 5 | ''' 6 | def count_th(word): 7 | 8 | # TBC 9 | 10 | pass 11 | -------------------------------------------------------------------------------- /recursive_count_th/test_count_th.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import random 3 | from count_th import * 4 | 5 | class Test(unittest.TestCase): 6 | 7 | def setUp(self): 8 | self.word = "" 9 | 10 | def test_count_th_empty(self): 11 | self.word = "" 12 | count = count_th(self.word) 13 | self.assertEqual(0, count) 14 | 15 | def test_count_th_single(self): 16 | self.word = "abcthxyz" 17 | count = count_th(self.word) 18 | self.assertEqual(1, count) 19 | 20 | def test_count_th_multiple(self): 21 | self.word = "abcthefthghith" 22 | count = count_th(self.word) 23 | self.assertEqual(3, count) 24 | 25 | def test_count_backwards(self): 26 | self.word = "thhtthht" 27 | count = count_th(self.word) 28 | self.assertEqual(2, count) 29 | 30 | def test_count_th_mixedcase(self): 31 | self.word = "THtHThth" 32 | count = count_th(self.word) 33 | self.assertEqual(1, count) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /robot_sort/robot_sort.py: -------------------------------------------------------------------------------- 1 | class SortingRobot: 2 | def __init__(self, l): 3 | """ 4 | SortingRobot takes a list and sorts it. 5 | """ 6 | self._list = l # The list the robot is tasked with sorting 7 | self._item = None # The item the robot is holding 8 | self._position = 0 # The list position the robot is at 9 | self._light = "OFF" # The state of the robot's light 10 | self._time = 0 # A time counter (stretch) 11 | 12 | def can_move_right(self): 13 | """ 14 | Returns True if the robot can move right or False if it's 15 | at the end of the list. 16 | """ 17 | return self._position < len(self._list) - 1 18 | 19 | def can_move_left(self): 20 | """ 21 | Returns True if the robot can move left or False if it's 22 | at the start of the list. 23 | """ 24 | return self._position > 0 25 | 26 | def move_right(self): 27 | """ 28 | If the robot can move to the right, it moves to the right and 29 | returns True. Otherwise, it stays in place and returns False. 30 | This will increment the time counter by 1. 31 | """ 32 | self._time += 1 33 | if self._position < len(self._list) - 1: 34 | self._position += 1 35 | return True 36 | else: 37 | return False 38 | 39 | def move_left(self): 40 | """ 41 | If the robot can move to the left, it moves to the left and 42 | returns True. Otherwise, it stays in place and returns False. 43 | This will increment the time counter by 1. 44 | """ 45 | self._time += 1 46 | if self._position > 0: 47 | self._position -= 1 48 | return True 49 | else: 50 | return False 51 | 52 | def swap_item(self): 53 | """ 54 | The robot swaps its currently held item with the list item in front 55 | of it. 56 | This will increment the time counter by 1. 57 | """ 58 | self._time += 1 59 | # Swap the held item with the list item at the robot's position 60 | self._item, self._list[self._position] = self._list[self._position], self._item 61 | 62 | def compare_item(self): 63 | """ 64 | Compare the held item with the item in front of the robot: 65 | If the held item's value is greater, return 1. 66 | If the held item's value is less, return -1. 67 | If the held item's value is equal, return 0. 68 | If either item is None, return None. 69 | """ 70 | if self._item is None or self._list[self._position] is None: 71 | return None 72 | elif self._item > self._list[self._position]: 73 | return 1 74 | elif self._item < self._list[self._position]: 75 | return -1 76 | else: 77 | return 0 78 | 79 | def set_light_on(self): 80 | """ 81 | Turn on the robot's light 82 | """ 83 | self._light = "ON" 84 | def set_light_off(self): 85 | """ 86 | Turn off the robot's light 87 | """ 88 | self._light = "OFF" 89 | def light_is_on(self): 90 | """ 91 | Returns True if the robot's light is on and False otherwise. 92 | """ 93 | return self._light == "ON" 94 | 95 | def sort(self): 96 | """ 97 | Sort the robot's list. 98 | """ 99 | # Fill this out 100 | pass 101 | 102 | 103 | if __name__ == "__main__": 104 | # Test our your implementation from the command line 105 | # with `python robot_sort.py` 106 | 107 | l = [15, 41, 58, 49, 26, 4, 28, 8, 61, 60, 65, 21, 78, 14, 35, 90, 54, 5, 0, 87, 82, 96, 43, 92, 62, 97, 69, 94, 99, 93, 76, 47, 2, 88, 51, 40, 95, 6, 23, 81, 30, 19, 25, 91, 18, 68, 71, 9, 66, 1, 45, 33, 3, 72, 16, 85, 27, 59, 64, 39, 32, 24, 38, 84, 44, 80, 11, 73, 42, 20, 10, 29, 22, 98, 17, 48, 52, 67, 53, 74, 77, 37, 63, 31, 7, 75, 36, 89, 70, 34, 79, 83, 13, 57, 86, 12, 56, 50, 55, 46] 108 | 109 | robot = SortingRobot(l) 110 | 111 | robot.sort() 112 | print(robot._list) -------------------------------------------------------------------------------- /robot_sort/test_robot.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import random 3 | from robot_sort import SortingRobot 4 | 5 | class Test(unittest.TestCase): 6 | 7 | def setUp(self): 8 | self.small_list = [5, 4, 3, 2, 1] 9 | self.medium_list = [11, 13, 7, 17, 9, 20, 1, 21, 2, 4, 22, 16, 15, 10, 23, 19, 8, 3, 5, 14, 6, 0, 24, 12, 18] 10 | self.large_list = [20, 77, 45, 16, 15, 91, 12, 6, 24, 89, 53, 19, 85, 56, 13, 74, 48, 98, 9, 92, 25, 35, 54, 44, 50, 5, 75, 34, 2, 42, 87, 49, 76, 52, 43, 23, 7, 80, 66, 14, 46, 90, 88, 40, 97, 10, 57, 63, 1, 18, 67, 79, 96, 27, 73, 28, 32, 61, 30, 8, 17, 93, 26, 51, 60, 55, 62, 31, 47, 64, 39, 22, 99, 95, 83, 70, 38, 69, 36, 41, 37, 65, 84, 3, 29, 58, 0, 94, 4, 11, 33, 86, 21, 81, 72, 82, 59, 71, 68, 78] 11 | self.large_varied_list = [1, -38, -95, 4, 23, -73, -65, -36, 85, 2, 58, -26, -55, 96, 55, -76, 64, 45, 69, 36, 69, 47, 29, -47, 13, 89, -57, -88, -87, 54, 60, 56, -98, -78, 59, 93, -41, -74, 73, -35, -23, -79, -35, 46, -18, -18, 37, -64, 14, -57, -2, 15, -85, 45, -73, -2, 79, -87, -100, 21, -51, 22, 26, -59, 81, 59, -24, 24, -81, 43, 61, 52, 38, -88, -95, 87, -57, -37, -65, -47, -3, 21, -77, 98, 25, 1, -36, 39, 78, 47, -35, -40, -69, -81, 11, -47, 21, 25, -53, -31] 12 | self.random_list = [random.randint(0, 100) for i in range(0, 100)] 13 | 14 | def test_sorting_small_list(self): 15 | robot = SortingRobot(self.small_list) 16 | robot.sort() 17 | self.assertEqual(robot._list, sorted(self.small_list)) 18 | 19 | def test_sorting_medium_list(self): 20 | robot = SortingRobot(self.medium_list) 21 | robot.sort() 22 | self.assertEqual(robot._list, sorted(self.medium_list)) 23 | 24 | def test_sorting_large_list(self): 25 | robot = SortingRobot(self.large_list) 26 | robot.sort() 27 | self.assertEqual(robot._list, sorted(self.large_list)) 28 | 29 | def test_sorting_large_varied_list(self): 30 | robot = SortingRobot(self.large_varied_list) 31 | robot.sort() 32 | self.assertEqual(robot._list, sorted(self.large_varied_list)) 33 | 34 | def test_sorting_random_list(self): 35 | robot = SortingRobot(self.random_list) 36 | robot.sort() 37 | self.assertEqual(robot._list, sorted(self.random_list)) 38 | 39 | # def test_stretch_times(self): 40 | # robot = SortingRobot(self.small_list) 41 | # robot.sort() 42 | # self.assertLess(robot._time, 110) 43 | 44 | # robot = SortingRobot(self.medium_list) 45 | # robot.sort() 46 | # print(robot._time) 47 | # self.assertLess(robot._time, 1948) 48 | 49 | # robot = SortingRobot(self.large_list) 50 | # robot.sort() 51 | # print(robot._time) 52 | # self.assertLess(robot._time, 27513) 53 | 54 | # robot = SortingRobot(self.large_varied_list) 55 | # robot.sort() 56 | # print(robot._time) 57 | # self.assertLess(robot._time, 28308) 58 | 59 | 60 | if __name__ == '__main__': 61 | unittest.main() 62 | --------------------------------------------------------------------------------