mirror of
https://github.com/donnemartin/interactive-coding-challenges.git
synced 2024-03-22 13:11:13 +08:00
commit
763fe6b392
235
README.md
235
README.md
@ -3,14 +3,21 @@
|
||||
<img src="https://raw.githubusercontent.com/donnemartin/interactive-coding-challenges/master/images/cover_challenge.gif">
|
||||
</p>
|
||||
|
||||
## April 2017 - Huge Update!
|
||||
|
||||
**Overhauled** to now include **120 challenges and solutions** and added [Anki Flash Cards](#anki-flashcards-coding-and-design).
|
||||
|
||||
Also included are **unit tested reference implementations** of various [data structures](#reference-implementations-data-structures) and [algorithms](#reference-implementations-algorithms).
|
||||
|
||||
interactive-coding-challenges
|
||||
============
|
||||
|
||||
**Continually updated, interactive and test-driven coding challenges**.
|
||||
|
||||
Challenges focus on **algorithms** and **data structures** that are typically found in **coding interviews**.
|
||||
Challenges focus on **algorithms** and **data structures** found in **coding interviews**.
|
||||
|
||||
Each challenge has one or more reference solutions that are:
|
||||
|
||||
* Fully functional
|
||||
* Unit tested
|
||||
* Easy-to-understand
|
||||
@ -18,6 +25,7 @@ Each challenge has one or more reference solutions that are:
|
||||
Challenges will soon provide on-demand [incremental hints](https://github.com/donnemartin/interactive-coding-challenges/issues/22) to help you arrive at the optimal solution.
|
||||
|
||||
Notebooks also detail:
|
||||
|
||||
* Constraints
|
||||
* Test cases
|
||||
* Algorithms
|
||||
@ -31,9 +39,40 @@ Notebooks also detail:
|
||||
</p>
|
||||
<br/>
|
||||
|
||||
## Anki Flashcards: Coding and Design
|
||||
|
||||
<p align="center">
|
||||
<img src="http://i.imgur.com/b4YtAEN.png">
|
||||
<br/>
|
||||
</p>
|
||||
|
||||
The provided [Anki flashcard deck](https://apps.ankiweb.net/) uses spaced repetition to help you retain key concepts.
|
||||
|
||||
* [Coding deck](anki_cards/Coding.apkg)
|
||||
|
||||
Great for use while on-the-go.
|
||||
|
||||
### Design Resource: The System Design Primer
|
||||
|
||||
Looking for resources to help you prep for the **System Design** and **Object-Oriented Design interviews**?
|
||||
|
||||
<p align="center">
|
||||
<img src="http://i.imgur.com/zdCAkB3.png">
|
||||
<br/>
|
||||
</p>
|
||||
|
||||
Check out the sister repo [The System Design Primer](https://github.com/donnemartin/system-design-primer), which contains additional Anki decks:
|
||||
|
||||
* [System design deck](resources/flash_cards/System%20Design.apkg)
|
||||
* [System design exercises deck](resources/flash_cards/System%20Design%20Exercises.apkg)
|
||||
* [Object oriented design exercises deck](resources/flash_cards/OO%20Design.apkg)
|
||||
|
||||
<br/>
|
||||
![](https://camo.githubusercontent.com/e45e39c36eebcc4c66e1aecd4e4145112d8e88e3/687474703a2f2f692e696d6775722e636f6d2f6a6a3341354e382e706e67)
|
||||
|
||||
## Notebook Structure
|
||||
|
||||
Each challenge has two notebooks, a **challenge notebook** for you to solve and a **solution notebook** for reference.
|
||||
Each challenge has two notebooks, a **challenge notebook** with unit tests for you to solve and a **solution notebook** for reference.
|
||||
|
||||
### Problem Statement
|
||||
|
||||
@ -66,28 +105,74 @@ Each challenge has two notebooks, a **challenge notebook** for you to solve and
|
||||
* [Challenge Notebook] Unit test for your code. Expected to fail until you solve the challenge.
|
||||
* [Solution Notebook] Unit test for the reference solution(s).
|
||||
|
||||
## Future Development
|
||||
|
||||
Challenges, solutions, and unit tests are presented in the form of **IPython/Jupyter Notebooks**.
|
||||
|
||||
* Notebooks currently contain mostly Python solutions (tested on both Python 2.7 and Python 3.4), but can be extended to include [44 supported languages](https://github.com/ipython/ipython/wiki/IPython-kernels-for-other-languages)
|
||||
* Repo will be **continually updated** with new solutions and challenges
|
||||
* [Contributions](#contributing) are welcome!
|
||||
|
||||
## Index
|
||||
|
||||
### Challenges Categories
|
||||
|
||||
* [Arrays and Strings](#arrays-and-strings)
|
||||
* [Linked Lists](#linked-lists)
|
||||
* [Stacks and Queues](#stacks-and-queues)
|
||||
* [Graphs and Trees](#graphs-and-trees)
|
||||
* [Sorting](#sorting)
|
||||
* [Recursion and Dynamic Programming](#recursion-and-dynamic-programming)
|
||||
* [Bit Manipulation](#bit-manipulation)
|
||||
* [Scalability and Memory Limits](#scalability-and-memory-limits)
|
||||
* [Concurrency](#concurrency)
|
||||
* [Online Judges](#online-judges)
|
||||
**Format**: Challenge Category - Number of Challenges
|
||||
|
||||
* [Arrays and Strings](#arrays-and-strings) - 10
|
||||
* [Linked Lists](#linked-lists) - 8
|
||||
* [Stacks and Queues](#stacks-and-queues) - 8
|
||||
* [Graphs and Trees](#graphs-and-trees) - 21
|
||||
* [Sorting](#sorting) - 10
|
||||
* [Recursion and Dynamic Programming](#recursion-and-dynamic-programming) - 17
|
||||
* [Mathematics and Probability](#mathematics-and-probability) - 6
|
||||
* [Bit Manipulation](#bit-manipulation) - 8
|
||||
* [Online Judges](#online-judges) - 16
|
||||
* [System Design](https://github.com/donnemartin/system-design-primer#system-design-interview-questions-with-solutions) - 8
|
||||
* [Object Oriented Design](https://github.com/donnemartin/system-design-primer#object-oriented-design-interview-questions-with-solutions) - 8
|
||||
|
||||
**Total number of challenges: 120**
|
||||
|
||||
### Reference Implementations: Data Structures
|
||||
|
||||
Unit tested, fully functional implementations of the following data structures:
|
||||
|
||||
* [Linked List](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/linked_lists/linked_list/linked_list_solution.ipynb)
|
||||
* [Stack](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/stacks_queues/stack/stack_solution.ipynb)
|
||||
* [Queue](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/stacks_queues/queue_list/queue_list_solution.ipynb)
|
||||
* [Binary Search Tree](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst/bst_solution.ipynb)
|
||||
* [Graph](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph/graph_solution.ipynb)
|
||||
* [Min Heap](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/min_heap/min_heap_solution.ipynb)
|
||||
* [Trie](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/trie/trie_solution.ipynb)
|
||||
* [Priority Queue](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/priority_queue/priority_queue_solution.ipynb)
|
||||
* [Hash Map](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/hash_map/hash_map_solution.ipynb)
|
||||
|
||||
### Reference Implementations: Algorithms
|
||||
|
||||
Unit tested, fully functional implementations of the following algorithms:
|
||||
|
||||
* [Selection Sort](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/selection_sort/selection_sort_solution.ipynb)
|
||||
* [Insertion Sort](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/insertion_sort/insertion_sort_solution.ipynb)
|
||||
* [Quick Sort](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/quick_sort/quick_sort_solution.ipynb)
|
||||
* [Merge Sort](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/merge_sort/merge_sort_solution.ipynb)
|
||||
* [Radix Sort](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/radix_sort/radix_sort_solution.ipynb)
|
||||
* [Topological Sort](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_build_order/build_order_solution.ipynb)
|
||||
* [Tree Depth-First Search (Pre-, In-, Post-Order)](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_dfs/dfs_solution.ipynb)
|
||||
* [Tree Breadth-First Search](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_bfs/bfs_solution.ipynb)
|
||||
* [Graph Depth-First Search](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_dfs/dfs_solution.ipynb)
|
||||
* [Graph Breadth-First Search](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_bfs/bfs_solution.ipynb)
|
||||
* [Dijkstra's Shortest Path](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_shortest_path/graph_shortest_path_solution.ipynb)
|
||||
* [Unweighted Graph Shortest Path](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_shortest_path_unweighted/shortest_path_solution.ipynb)
|
||||
* [Knapsack 0/1](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/knapsack_01/knapsack_solution.ipynb)
|
||||
* [Knapsack Unbounded](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/knapsack_unbounded/knapsack_unbounded_solution.ipynb)
|
||||
* [Sieve of Eratosthenes](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/generate_primes/check_prime_solution.ipynb)
|
||||
|
||||
### Reference Implementations: TODO
|
||||
|
||||
* [A*](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Bellman-Ford](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Bloom Filter](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Convex Hull](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Fisher-Yates Shuffle](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Kruskal's](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Max Flow](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Prim's](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Rabin-Karp](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Traveling Salesman](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Union Find](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
|
||||
### Installing and Running Challenges
|
||||
|
||||
@ -98,7 +183,7 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
|
||||
### Misc
|
||||
|
||||
* [Contributing](#contributing)
|
||||
* [Contributing](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)
|
||||
* [Credits](#credits)
|
||||
* [Contact Info](#contact-info)
|
||||
* [License](#license)
|
||||
@ -122,6 +207,8 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
| Determine if a string is a rotation of another | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/rotation/rotation_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/rotation/rotation_solution.ipynb) |
|
||||
| Compress a string | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/compress/compress_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/compress/compress_solution.ipynb) |
|
||||
| Reverse characters in a string | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/reverse_string/reverse_string_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/reverse_string/reverse_string_solution.ipynb) |
|
||||
| Given two strings, find the single different char | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/str_diff/str_diff_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/str_diff/str_diff_solution.ipynb) |
|
||||
| Find two indices that sum to a specific value | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/two_sum/two_sum_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/two_sum/two_sum_solution.ipynb) |
|
||||
| Implement a hash table | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/hash_map/hash_map_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/hash_map/hash_map_solution.ipynb) |
|
||||
| Implement fizz buzz | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/fizz_buzz/fizz_buzz_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/fizz_buzz/fizz_buzz_solution.ipynb) |
|
||||
| Find the first non-repeated character in a string | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
@ -132,7 +219,7 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
| Add a challenge | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/donnemartin/interactive-coding-challenges/master/images/linked_lists_wikipedia.png">
|
||||
</p>
|
||||
<br/>
|
||||
@ -153,7 +240,7 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
| Add a challenge | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/donnemartin/interactive-coding-challenges/master/images/stack_queue_wikipedia.png">
|
||||
</p>
|
||||
<br/>
|
||||
@ -169,10 +256,11 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
| Sort a stack using another stack as a buffer | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/stacks_queues/sort_stack/sort_stack_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/stacks_queues/sort_stack/sort_stack_solution.ipynb) |
|
||||
| Implement a stack | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/stacks_queues/stack/stack_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/stacks_queues/stack/stack_solution.ipynb) |
|
||||
| Implement a queue | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/stacks_queues/queue_list/queue_list_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/stacks_queues/queue_list/queue_list_solution.ipynb) |
|
||||
| Implement a priority queue backed by an array | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/priority_queue/priority_queue_challenge)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/arrays_strings/priority_queue/priority_queue_solution.ipynb) |
|
||||
| Add a challenge | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/donnemartin/interactive-coding-challenges/master/images/binary_tree_wikipedia.png">
|
||||
</p>
|
||||
<br/>
|
||||
@ -189,20 +277,23 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
| Check if a binary tree is balanced | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/check_balance/check_balance_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/check_balance/check_balance_solution.ipynb) |
|
||||
| Determine if a tree is a valid binary search tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst_validate/bst_validate_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst_validate/bst_validate_solution.ipynb) |
|
||||
| Find the in-order successor of a given node in a binary search tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst_successor/bst_successor_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst_successor/bst_successor_solution.ipynb) |
|
||||
| Find the second largest node in a binary search tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst_second_largest/bst_second_largest_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst_second_largest/bst_second_largest_solution.ipynb) |
|
||||
| Find the lowest common ancestor | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_lca/tree_lca_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_lca/tree_lca_solution.ipynb) |
|
||||
| Invert a binary tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/invert_tree/invert_tree_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/invert_tree/invert_tree_solution.ipynb) |
|
||||
| Implement a binary search tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst/bst_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst/bst_solution.ipynb) |
|
||||
| Implement a min heap | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/min_heap/min_heap_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/min_heap/min_heap_solution.ipynb) |
|
||||
| Implement a trie | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/trie/trie_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/trie/trie_solution.ipynb) |
|
||||
| Implement depth-first search on a graph | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_dfs/dfs_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_dfs/dfs_solution.ipynb) |
|
||||
| Implement breadth-first search on a graph | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_bfs/bfs_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_bfs/bfs_solution.ipynb) |
|
||||
| Determine if there is a path between two nodes in a graph | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_path_exists/path_exists_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_path_exists/path_exists_solution.ipynb) |
|
||||
| Implement a graph | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph/graph_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph/graph_solution.ipynb) |
|
||||
| Print a tree using pre-order traversal without recursion | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Determine the lowest common ancestor of two nodes | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Transform a binary tree into a heap | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Implement a right and left rotation on a tree | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Check if a binary tree is binary search tree | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Find a build order given a list of projects and dependencies. | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_build_order/build_order_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_build_order/build_order_solution.ipynb) |
|
||||
| Find the shortest path in a weighted graph. | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_shortest_path/graph_shortest_path_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_shortest_path/graph_shortest_path_solution.ipynb) |
|
||||
| Find the shortest path in an unweighted graph. | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_shortest_path_unweighted/shortest_path_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_shortest_path_unweighted/shortest_path_solution.ipynb) |
|
||||
| Add a challenge | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
<p align="center">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif">
|
||||
</p>
|
||||
<br/>
|
||||
@ -215,16 +306,21 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
| Implement insertion sort | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/insertion_sort/insertion_sort_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/insertion_sort/insertion_sort_solution.ipynb) |
|
||||
| Implement quick sort | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/quick_sort/quick_sort_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/quick_sort/quick_sort_solution.ipynb) |
|
||||
| Implement merge sort | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/merge_sort/merge_sort_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/merge_sort/merge_sort_solution.ipynb) |
|
||||
| Implement radix sort | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/radix_sort/radix_sort_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/radix_sort/radix_sort_solution.ipynb) |
|
||||
| Sort an array of strings so all anagrams are next to each other | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/anagrams/anagrams_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/anagrams/anagrams_solution.ipynb) |
|
||||
| Find an item in a sorted, rotated array | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/rotated_array_search/rotated_array_search_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/rotated_array_search/rotated_array_search_solution.ipynb) |
|
||||
| Search a sorted matrix for an item | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/search_sorted_matrix/search_sorted_matrix_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/search_sorted_matrix/search_sorted_matrix_solution.ipynb) |
|
||||
| Find an int not in an input of n integers | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/new_int/new_int_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/new_int/new_int_solution.ipynb) |
|
||||
| Given sorted arrays A, B, merge B into A in sorted order | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/merge_into/merge_into_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/sorting_searching/merge_into/merge_into_solution.ipynb) |
|
||||
| Implement a stable selection sort | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Make an unstable sort stable | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Implement an efficient, in-place version of quicksort | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Given two sorted arrays, merge one into the other in sorted order | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Sort an array of strings so all anagrams are next to each other | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Find an element in a rotated and sorted array of integers | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Add a challenge | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/donnemartin/interactive-coding-challenges/master/images/fibonacci_wikipedia.png">
|
||||
</p>
|
||||
<br/>
|
||||
@ -234,20 +330,30 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
| Challenge | Static Notebooks |
|
||||
|--------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Implement fibonacci recursively, dynamically, and iteratively | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/fibonacci/fibonacci_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/fibonacci/fibonacci_solution.ipynb) |
|
||||
| Implement the Towers of Hanoi with 3 towers and N disks | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/hanoi/hanoi_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/hanoi/hanoi_solution.ipynb) |
|
||||
| Find the number of ways to represent n cents given an array of coins | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/coin_change_ways/coin_change_ways_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/coin_change_ways/coin_change_ways_solution.ipynb) |
|
||||
| Maximize items placed in a knapsack | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/knapsack_01/knapsack_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/knapsack_01/knapsack_solution.ipynb) |
|
||||
| Maximize unbounded items placed in a knapsack | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/knapsack_unbounded/knapsack_unbounded_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/knapsack_unbounded/knapsack_unbounded_solution.ipynb) |
|
||||
| Find the longest common substring | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/longest_common_substring/longest_common_substr_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/longest_common_substring/longest_common_substr_solution.ipynb) |
|
||||
| Find the longest increasing subsequence | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/longest_inc_subseq/longest_inc_subseq_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/longest_inc_subseq/longest_inc_subseq_solution.ipynb) |
|
||||
| Minimize the cost of matrix multiplication | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/matrix_mult/find_min_cost_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/matrix_mult/find_min_cost_solution.ipynb) |
|
||||
| Maximize stock prices given k transactions | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/max_profit_k/max_profit_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/max_profit_k/max_profit_solution.ipynb) |
|
||||
| Find the minimum number of ways to represent n cents given an array of coins | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/coin_change_min/coin_change_min_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/coin_change_min/coin_change_min_solution.ipynb) |
|
||||
| Find the unique number of ways to represent n cents given an array of coins | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/coin_change/coin_change_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/coin_change/coin_change_solution.ipynb) |
|
||||
| Print all valid combinations of n-pairs of parentheses | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_solution.ipynb) |
|
||||
| Navigate a maze | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/grid_path/grid_path_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/grid_path/grid_path_solution.ipynb) |
|
||||
| Print all subsets of a set | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/power_set/power_set_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/power_set/power_set_solution.ipynb) |
|
||||
| Print all permutations of a string | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/permutations/permutations_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/permutations/permutations_solution.ipynb) |
|
||||
| Find the magic index in an array | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/magic_index/magic_index_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/magic_index/magic_index_solution.ipynb) |
|
||||
| Find the number of ways to run up n steps | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/steps/steps_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/steps/steps_solution.ipynb) |
|
||||
| Implement the Towers of Hanoi with 3 towers and N disks | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/hanoi/hanoi_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/hanoi/hanoi_solution.ipynb) |
|
||||
| Implement factorial recursively, dynamically, and iteratively | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Perform a binary search on a sorted array of integers | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Print all subsets of a set | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Print all permutations of a string | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Print all combinations of a string | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Implement a paint fill function | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Find all permutations to represent n cents, given 1, 5, 10, 25 cent coins | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Add a challenge | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/donnemartin/interactive-coding-challenges/master/images/probability_distribution_wikipedia.png">
|
||||
</p>
|
||||
<br/>
|
||||
@ -256,15 +362,20 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
|
||||
| Challenge | Static Notebooks |
|
||||
|--------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Generate a list of primes | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/generate_primes/check_prime_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/generate_primes/check_prime_solution.ipynb) |
|
||||
| Find the digital root | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/add_digits/add_digits_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/add_digits/add_digits_solution.ipynb) |
|
||||
| Create a class supporting insert, max, min, mean, mode in O(1) | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/math_ops/math_ops_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/math_ops/math_ops_solution.ipynb) |
|
||||
| Determine if a number is a power of two | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/power_two/power_two_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/power_two/power_two_solution.ipynb) |
|
||||
| Add two numbers without the + or - sign | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/sum_of_two/sum_of_two_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/sum_of_two/sum_of_two_solution.ipynb) |
|
||||
| Subtract two numbers without the + or - sign | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/sub_two/sub_two_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/math_probability/sub_two/sub_two_solution.ipynb) |
|
||||
| Check if a number is prime | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Generate a list of primes | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Determine if two lines on a Cartesian plane intersect | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Using only add, implement multiply, subtract, and divide for ints | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Find the kth number such that the only prime factors are 3, 5, and 7 | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Add a challenge | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/donnemartin/interactive-coding-challenges/master/images/bit_manipulation_wikipedia.png">
|
||||
</p>
|
||||
<br/>
|
||||
@ -273,14 +384,19 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
|
||||
| Challenge | Static Notebooks |
|
||||
|--------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Given a number between 0 and 1, print the binary representation | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Determine the number of bits required to convert integer A to integer B | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Swap odd and even bits in an integer with as few instructions as possible | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Determine the number of 1 bits in the binary representation of a given integer | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Implement common bit manipulation operations | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/bit/bit_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/bit/bit_solution.ipynb) |
|
||||
| Determine number of bits to flip to convert a into b | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/bits_to_flip/bits_to_flip_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/bits_to_flip/bits_to_flip_solution.ipynb) |
|
||||
| Draw a line on a screen | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/draw_line/draw_line_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/draw_line/draw_line_solution.ipynb) |
|
||||
| Flip a bit to maximize the longest sequence of 1s | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/flip_bit/flip_bit_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/flip_bit/flip_bit_solution.ipynb) |
|
||||
| Get the next largest and next smallest numbers | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/get_next/get_next_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/get_next/get_next_solution.ipynb) |
|
||||
| Merge two binary numbers | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/insert_m_into_n/insert_m_into_n_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/insert_m_into_n/insert_m_into_n_solution.ipynb) |
|
||||
| Swap odd and even bits in an integer | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/pairwise_swap/pairwise_swap_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/pairwise_swap/pairwise_swap_solution.ipynb) |
|
||||
| Print the binary representation of a number between 0 and 1 | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/print_binary/print_binary_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/bit_manipulation/print_binary/print_binary_solution.ipynb) |
|
||||
| Determine the number of 1s in the binary representation of a given integer | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
| Add a challenge | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
|
||||
<br/>
|
||||
<p>
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/donnemartin/interactive-coding-challenges/master/images/logo_topcoder.png">
|
||||
</p>
|
||||
<br/>
|
||||
@ -289,6 +405,20 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup
|
||||
|
||||
| Challenge | Static Notebooks |
|
||||
|--------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Find the longest substring with at most k distinct chars | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/longest_substr_k_distinct/longest_substr_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/longest_substr_k_distinct/longest_substr_solution.ipynb) |
|
||||
| Find the highest product of three numbers | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/prod_three/prod_three_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/prod_three/prod_three_solution.ipynb) |
|
||||
| Maximize stocks profit from 1 buy and 1 sell | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/max_profit/max_profit_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/max_profit/max_profit_solution.ipynb) |
|
||||
| Move all zeroes in a list to the end | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/move_zeroes/move_zeroes_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/move_zeroes/move_zeroes_solution.ipynb) |
|
||||
| Find the products of every other int | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/mult_other_numbers/mult_other_numbers_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/mult_other_numbers/mult_other_numbers_solution.ipynb) |
|
||||
| Given a list of entries and exits, find the busiest period | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/busiest_period/busiest_period_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/busiest_period/busiest_period_solution.ipynb) |
|
||||
| Determine an island's perimeter | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/island_perimeter/island_perimeter_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/island_perimeter/island_perimeter_solution.ipynb) |
|
||||
| Format license keys | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/license_key/format_license_key_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/license_key/format_license_key_solution.ipynb) |
|
||||
| Find the longest absolute file path | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/longest_abs_file_path/longest_path_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/longest_abs_file_path/longest_path_solution.ipynb) |
|
||||
| Merge tuple ranges | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/merge_ranges/merge_ranges_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/merge_ranges/merge_ranges_solution.ipynb) |
|
||||
| Assign cookies | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/assign_cookies/assign_cookies_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/assign_cookies/assign_cookies_solution.ipynb) |
|
||||
| Determine if you can win in Nim | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/nim/nim_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/nim/nim_solution.ipynb) |
|
||||
| Check if a magazine could have been used to create a ransom note | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/ransom_note/ransom_note_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/ransom_note/ransom_note_solution.ipynb) |
|
||||
| Find the number of times a sentence can fit on a screen | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/sentence_screen_fit/sentence_screen_fit_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/sentence_screen_fit/sentence_screen_fit_solution.ipynb) |
|
||||
| Utopian tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/utopian_tree/utopian_tree_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/utopian_tree/utopian_tree_solution.ipynb) |
|
||||
| Maximizing xor | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/maximizing_xor/maximizing_xor_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/online_judges/maximizing_xor/maximizing_xor_solution.ipynb) |
|
||||
| Add a challenge | [Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md)│[Contribute](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) |
|
||||
@ -366,7 +496,7 @@ More information on Nose can be found [here](https://nose.readthedocs.org/en/lat
|
||||
|
||||
### Notebooks
|
||||
|
||||
Challenges are provided in the form of **IPython/Jupyter Notebooks** and have been **tested with Python 2.7 and Python 3.4**.
|
||||
Challenges are provided in the form of **IPython/Jupyter Notebooks** and have been **tested with Python 2.7 and Python 3.x**.
|
||||
|
||||
*If you need to install IPython/Jupyter Notebook, see the [Notebook Installation](#notebook-installation) section.*
|
||||
|
||||
@ -382,6 +512,7 @@ $ jupyter notebook
|
||||
```
|
||||
|
||||
This will launch your web browser with the list of challenge categories:
|
||||
|
||||
* Navigate to the **Challenge Notebook** you wish to solve
|
||||
* Run the cells within the challenge notebook (Cell->Run All)
|
||||
* This will result in an expected unit test error
|
||||
@ -392,11 +523,20 @@ To **debug** your solution with pdb, refer to the following [ticket](https://git
|
||||
|
||||
Note: If your solution is different from those listed in the Solution Notebook, consider submitting a pull request so others can benefit from your work. Review the [Contributing Guidelines](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) for details.
|
||||
|
||||
## Future Development
|
||||
|
||||
Challenges, solutions, and unit tests are presented in the form of **IPython/Jupyter Notebooks**.
|
||||
|
||||
* Notebooks currently contain mostly Python solutions (tested on both Python 2.7 and Python 3.x), but can be extended to include [40+ supported languages](https://github.com/ipython/ipython/wiki/IPython-kernels-for-other-languages)
|
||||
* Repo will be **continually updated** with new solutions and challenges
|
||||
* [Contributions](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) are welcome!
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome!
|
||||
|
||||
Review the [Contributing Guidelines](https://github.com/donnemartin/interactive-coding-challenges/blob/master/CONTRIBUTING.md) for details on how to:
|
||||
|
||||
* Submit issues
|
||||
* Add solutions to existing challenges
|
||||
* Add new challenges
|
||||
@ -407,6 +547,11 @@ Review the [Contributing Guidelines](https://github.com/donnemartin/interactive-
|
||||
|
||||
* [Cracking the Coding Interview](http://www.amazon.com/Cracking-Coding-Interview-Programming-Questions/dp/098478280X) | [GitHub Solutions](https://github.com/gaylemcd/ctci)
|
||||
* [Programming Interviews Exposed](http://www.amazon.com/gp/product/1118261364/)
|
||||
* [The Algorithm Design Manual](http://www.amazon.com/Algorithm-Design-Manual-Steve-Skiena/dp/0387948600) | [Solutions](http://www.algorithm.cs.sunysb.edu/algowiki/index.php/The_Algorithms_Design_Manual_(Second_Edition))
|
||||
* [CareerCup](http://www.careercup.com/)
|
||||
* [Quora](http://www.quora.com/)
|
||||
* [HackerRank](https://www.hackerrank.com)
|
||||
* [LeetCode](https://leetcode.com/)
|
||||
|
||||
### Images
|
||||
|
||||
|
BIN
anki_cards/Coding.apkg
Normal file
BIN
anki_cards/Coding.apkg
Normal file
Binary file not shown.
0
arrays_strings/priority_queue/__init__.py
Normal file
0
arrays_strings/priority_queue/__init__.py
Normal file
41
arrays_strings/priority_queue/priority_queue.py
Normal file
41
arrays_strings/priority_queue/priority_queue.py
Normal file
@ -0,0 +1,41 @@
|
||||
import sys
|
||||
|
||||
|
||||
class PriorityQueueNode(object):
|
||||
|
||||
def __init__(self, obj, key):
|
||||
self.obj = obj
|
||||
self.key = key
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.obj) + ': ' + str(self.key)
|
||||
|
||||
|
||||
class PriorityQueue(object):
|
||||
|
||||
def __init__(self):
|
||||
self.array = []
|
||||
|
||||
def __len__(self):
|
||||
return len(self.array)
|
||||
|
||||
def insert(self, node):
|
||||
self.array.append(node)
|
||||
return self.array[-1]
|
||||
|
||||
def extract_min(self):
|
||||
if not self.array:
|
||||
return None
|
||||
minimum = sys.maxsize
|
||||
for index, node in enumerate(self.array):
|
||||
if node.key < minimum:
|
||||
minimum = node.key
|
||||
minimum_index = index
|
||||
return self.array.pop(minimum_index)
|
||||
|
||||
def decrease_key(self, obj, new_key):
|
||||
for node in self.array:
|
||||
if node.obj is obj:
|
||||
node.key = new_key
|
||||
return node
|
||||
return None
|
209
arrays_strings/priority_queue/priority_queue_challenge.ipynb
Normal file
209
arrays_strings/priority_queue/priority_queue_challenge.ipynb
Normal file
@ -0,0 +1,209 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement a priority queue backed by an array.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Do we expect the methods to be insert, extract_min, and decrease_key?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume there aren't any duplicate keys?\n",
|
||||
" * Yes\n",
|
||||
"* Do we need to validate inputs?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"### insert\n",
|
||||
"\n",
|
||||
"* `insert` general case -> inserted node\n",
|
||||
"\n",
|
||||
"### extract_min\n",
|
||||
"\n",
|
||||
"* `extract_min` from an empty list -> None\n",
|
||||
"* `extract_min` general case -> min node\n",
|
||||
"\n",
|
||||
"### decrease_key\n",
|
||||
"\n",
|
||||
"* `decrease_key` an invalid key -> None\n",
|
||||
"* `decrease_key` general case -> updated node"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](https://github.com/donnemartin/interactive-coding-challenges/arrays_strings/priority_queue/priority_queue_solution.ipynb). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class PriorityQueueNode(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, obj, key):\n",
|
||||
" self.obj = obj\n",
|
||||
" self.key = key\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return str(self.obj) + ': ' + str(self.key)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class PriorityQueue(object):\n",
|
||||
"\n",
|
||||
" def __init__(self):\n",
|
||||
" self.array = []\n",
|
||||
"\n",
|
||||
" def __len__(self):\n",
|
||||
" return len(self.array)\n",
|
||||
"\n",
|
||||
" def insert(self, node):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def extract_min(self):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def decrease_key(self, obj, new_key):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_priority_queue.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestPriorityQueue(object):\n",
|
||||
"\n",
|
||||
" def test_priority_queue(self):\n",
|
||||
" priority_queue = PriorityQueue()\n",
|
||||
" assert_equal(priority_queue.extract_min(), None)\n",
|
||||
" priority_queue.insert(PriorityQueueNode('a', 20))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('b', 5))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('c', 15))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('d', 22))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('e', 40))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('f', 3))\n",
|
||||
" priority_queue.decrease_key('f', 2)\n",
|
||||
" priority_queue.decrease_key('a', 19)\n",
|
||||
" mins = []\n",
|
||||
" while priority_queue.array:\n",
|
||||
" mins.append(priority_queue.extract_min().key)\n",
|
||||
" assert_equal(mins, [2, 5, 15, 19, 22, 40])\n",
|
||||
" print('Success: test_min_heap')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestPriorityQueue()\n",
|
||||
" test.test_priority_queue()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook](https://github.com/donnemartin/interactive-coding-challenges/arrays_strings/priority_queue/priority_queue_solution.ipynb) for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
276
arrays_strings/priority_queue/priority_queue_solution.ipynb
Normal file
276
arrays_strings/priority_queue/priority_queue_solution.ipynb
Normal file
@ -0,0 +1,276 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement a priority queue backed by an array.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Do we expect the methods to be insert, extract_min, and decrease_key?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume there aren't any duplicate keys?\n",
|
||||
" * Yes\n",
|
||||
"* Do we need to validate inputs?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"### insert\n",
|
||||
"\n",
|
||||
"* `insert` general case -> inserted node\n",
|
||||
"\n",
|
||||
"### extract_min\n",
|
||||
"\n",
|
||||
"* `extract_min` from an empty list -> None\n",
|
||||
"* `extract_min` general case -> min node\n",
|
||||
"\n",
|
||||
"### decrease_key\n",
|
||||
"\n",
|
||||
"* `decrease_key` an invalid key -> None\n",
|
||||
"* `decrease_key` general case -> updated node"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"### insert\n",
|
||||
"\n",
|
||||
"* Append to the internal array.\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(1)\n",
|
||||
"* Space: O(1)\n",
|
||||
"\n",
|
||||
"### extract_min\n",
|
||||
"\n",
|
||||
"* Loop through each item in the internal array\n",
|
||||
" * Update the min value as needed\n",
|
||||
"* Remove the min element from the array and return it\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(1)\n",
|
||||
"\n",
|
||||
"### decrease_key\n",
|
||||
"\n",
|
||||
"* Loop through each item in the internal array to find the matching input\n",
|
||||
" * Update the matching element's key\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting priority_queue.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile priority_queue.py\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class PriorityQueueNode(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, obj, key):\n",
|
||||
" self.obj = obj\n",
|
||||
" self.key = key\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return str(self.obj) + ': ' + str(self.key)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class PriorityQueue(object):\n",
|
||||
"\n",
|
||||
" def __init__(self):\n",
|
||||
" self.array = []\n",
|
||||
"\n",
|
||||
" def __len__(self):\n",
|
||||
" return len(self.array)\n",
|
||||
"\n",
|
||||
" def insert(self, node):\n",
|
||||
" self.array.append(node)\n",
|
||||
" return self.array[-1]\n",
|
||||
"\n",
|
||||
" def extract_min(self):\n",
|
||||
" if not self.array:\n",
|
||||
" return None\n",
|
||||
" minimum = sys.maxsize\n",
|
||||
" for index, node in enumerate(self.array):\n",
|
||||
" if node.key < minimum:\n",
|
||||
" minimum = node.key\n",
|
||||
" minimum_index = index\n",
|
||||
" return self.array.pop(minimum_index)\n",
|
||||
"\n",
|
||||
" def decrease_key(self, obj, new_key):\n",
|
||||
" for node in self.array:\n",
|
||||
" if node.obj is obj:\n",
|
||||
" node.key = new_key\n",
|
||||
" return node\n",
|
||||
" return None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run priority_queue.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_priority_queue.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_priority_queue.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestPriorityQueue(object):\n",
|
||||
"\n",
|
||||
" def test_priority_queue(self):\n",
|
||||
" priority_queue = PriorityQueue()\n",
|
||||
" assert_equal(priority_queue.extract_min(), None)\n",
|
||||
" priority_queue.insert(PriorityQueueNode('a', 20))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('b', 5))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('c', 15))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('d', 22))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('e', 40))\n",
|
||||
" priority_queue.insert(PriorityQueueNode('f', 3))\n",
|
||||
" priority_queue.decrease_key('f', 2)\n",
|
||||
" priority_queue.decrease_key('a', 19)\n",
|
||||
" mins = []\n",
|
||||
" while priority_queue.array:\n",
|
||||
" mins.append(priority_queue.extract_min().key)\n",
|
||||
" assert_equal(mins, [2, 5, 15, 19, 22, 40])\n",
|
||||
" print('Success: test_min_heap')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestPriorityQueue()\n",
|
||||
" test.test_priority_queue()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_min_heap\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_priority_queue.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
30
arrays_strings/priority_queue/test_priority_queue.py
Normal file
30
arrays_strings/priority_queue/test_priority_queue.py
Normal file
@ -0,0 +1,30 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestPriorityQueue(object):
|
||||
|
||||
def test_priority_queue(self):
|
||||
priority_queue = PriorityQueue()
|
||||
assert_equal(priority_queue.extract_min(), None)
|
||||
priority_queue.insert(PriorityQueueNode('a', 20))
|
||||
priority_queue.insert(PriorityQueueNode('b', 5))
|
||||
priority_queue.insert(PriorityQueueNode('c', 15))
|
||||
priority_queue.insert(PriorityQueueNode('d', 22))
|
||||
priority_queue.insert(PriorityQueueNode('e', 40))
|
||||
priority_queue.insert(PriorityQueueNode('f', 3))
|
||||
priority_queue.decrease_key('f', 2)
|
||||
priority_queue.decrease_key('a', 19)
|
||||
mins = []
|
||||
while priority_queue.array:
|
||||
mins.append(priority_queue.extract_min().key)
|
||||
assert_equal(mins, [2, 5, 15, 19, 22, 40])
|
||||
print('Success: test_min_heap')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestPriorityQueue()
|
||||
test.test_priority_queue()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
arrays_strings/str_diff/__init__.py
Normal file
0
arrays_strings/str_diff/__init__.py
Normal file
165
arrays_strings/str_diff/str_diff_challenge.ipynb
Normal file
165
arrays_strings/str_diff/str_diff_challenge.ipynb
Normal file
@ -0,0 +1,165 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the single different char between two strings.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the strings are ASCII?\n",
|
||||
" * Yes\n",
|
||||
"* Is case important?\n",
|
||||
" * The strings are lower case\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No, check for None\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None input -> TypeError\n",
|
||||
"* 'abcd', 'abcde' -> 'e'\n",
|
||||
"* 'aaabbcdd', 'abdbacade' -> 'e'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def find_diff(self, s, t):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_str_diff.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestFindDiff(object):\n",
|
||||
"\n",
|
||||
" def test_find_diff(self):\n",
|
||||
" solution = Solution()\n",
|
||||
" assert_raises(TypeError, solution.find_diff, None)\n",
|
||||
" assert_equal(solution.find_diff('abcd', 'abcde'), 'e')\n",
|
||||
" assert_equal(solution.find_diff('aaabbcdd', 'abdbacade'), 'e')\n",
|
||||
" print('Success: test_find_diff')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestFindDiff()\n",
|
||||
" test.test_find_diff()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
215
arrays_strings/str_diff/str_diff_solution.ipynb
Normal file
215
arrays_strings/str_diff/str_diff_solution.ipynb
Normal file
@ -0,0 +1,215 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the single different char between two strings.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the strings are ASCII?\n",
|
||||
" * Yes\n",
|
||||
"* Is case important?\n",
|
||||
" * The strings are lower case\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No, check for None\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None input -> TypeError\n",
|
||||
"* 'abcd', 'abcde' -> 'e'\n",
|
||||
"* 'aaabbcdd', 'abdbacade' -> 'e'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"### Dictionary\n",
|
||||
"\n",
|
||||
"* Keep a dictionary of seen values in s\n",
|
||||
"* Loop through t, decrementing the seen values\n",
|
||||
" * If the char is not there or if the decrement results in a negative value, return the char\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(m+n), where m and n are the lengths of s, t\n",
|
||||
"* Space: O(h), for the dict, where h is the unique chars in s\n",
|
||||
"\n",
|
||||
"### XOR\n",
|
||||
"\n",
|
||||
"* XOR the two strings, which will isolate the differing char\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(m+n), where m and n are the lengths of s, t\n",
|
||||
"* Space: O(1), for the dict, where h is the unique chars in s"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def find_diff(self, str1, str2):\n",
|
||||
" if str1 is None or str2 is None:\n",
|
||||
" raise TypeError('str1 or str2 cannot be None')\n",
|
||||
" seen = {}\n",
|
||||
" for char in str1:\n",
|
||||
" if char in seen:\n",
|
||||
" seen[char] += 1\n",
|
||||
" else:\n",
|
||||
" seen[char] = 1\n",
|
||||
" for char in str2:\n",
|
||||
" try:\n",
|
||||
" seen[char] -= 1\n",
|
||||
" except KeyError:\n",
|
||||
" return char\n",
|
||||
" if seen[char] < 0:\n",
|
||||
" return char\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
" def find_diff_xor(self, str1, str2):\n",
|
||||
" if str1 is None or str2 is None:\n",
|
||||
" raise TypeError('str1 or str2 cannot be None')\n",
|
||||
" result = 0\n",
|
||||
" for char in str1:\n",
|
||||
" result ^= ord(char)\n",
|
||||
" for char in str2:\n",
|
||||
" result ^= ord(char)\n",
|
||||
" return chr(result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_str_diff.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_str_diff.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestFindDiff(object):\n",
|
||||
"\n",
|
||||
" def test_find_diff(self):\n",
|
||||
" solution = Solution()\n",
|
||||
" assert_raises(TypeError, solution.find_diff, None)\n",
|
||||
" assert_equal(solution.find_diff('abcd', 'abcde'), 'e')\n",
|
||||
" assert_equal(solution.find_diff('aaabbcdd', 'abdbacade'), 'e')\n",
|
||||
" print('Success: test_find_diff')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestFindDiff()\n",
|
||||
" test.test_find_diff()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_find_diff\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_str_diff.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
20
arrays_strings/str_diff/test_str_diff.py
Normal file
20
arrays_strings/str_diff/test_str_diff.py
Normal file
@ -0,0 +1,20 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestFindDiff(object):
|
||||
|
||||
def test_find_diff(self):
|
||||
solution = Solution()
|
||||
assert_raises(TypeError, solution.find_diff, None)
|
||||
assert_equal(solution.find_diff('abcd', 'abcde'), 'e')
|
||||
assert_equal(solution.find_diff('aaabbcdd', 'abdbacade'), 'e')
|
||||
print('Success: test_find_diff')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestFindDiff()
|
||||
test.test_find_diff()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
arrays_strings/two_sum/__init__.py
Normal file
0
arrays_strings/two_sum/__init__.py
Normal file
23
arrays_strings/two_sum/test_two_sum.py
Normal file
23
arrays_strings/two_sum/test_two_sum.py
Normal file
@ -0,0 +1,23 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestTwoSum(object):
|
||||
|
||||
def test_two_sum(self):
|
||||
solution = Solution()
|
||||
assert_raises(TypeError, solution.two_sum, None, None)
|
||||
assert_raises(ValueError, solution.two_sum, [], 0)
|
||||
target = 7
|
||||
nums = [1, 3, 2, -7, 5]
|
||||
expected = [2, 4]
|
||||
assert_equal(solution.two_sum(nums, target), expected)
|
||||
print('Success: test_two_sum')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestTwoSum()
|
||||
test.test_two_sum()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
170
arrays_strings/two_sum/two_sum_challenge.ipynb
Normal file
170
arrays_strings/two_sum/two_sum_challenge.ipynb
Normal file
@ -0,0 +1,170 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given an array, find the two indices that sum to a specific value.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is there exactly one solution?\n",
|
||||
" * Yes\n",
|
||||
"* Is there always a solution?\n",
|
||||
" * Yes\n",
|
||||
"* Is the array an array of ints?\n",
|
||||
" * Yes\n",
|
||||
"* Is the array sorted?\n",
|
||||
" No\n",
|
||||
"* Are negative values possible?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None input -> TypeError\n",
|
||||
"* [] -> ValueError\n",
|
||||
"* [1, 3, 2, -7, 5], 7 -> [2, 4]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def two_sum(self, val):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_two_sum.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestTwoSum(object):\n",
|
||||
"\n",
|
||||
" def test_two_sum(self):\n",
|
||||
" solution = Solution()\n",
|
||||
" assert_raises(TypeError, solution.two_sum, None)\n",
|
||||
" assert_equal(solution.two_sum(0), 0)\n",
|
||||
" print('Success: test_two_sum')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestTwoSum()\n",
|
||||
" test.test_two_sum()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
271
arrays_strings/two_sum/two_sum_solution.ipynb
Normal file
271
arrays_strings/two_sum/two_sum_solution.ipynb
Normal file
@ -0,0 +1,271 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given an array, find the two indices that sum to a specific value.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is there exactly one solution?\n",
|
||||
" * Yes\n",
|
||||
"* Is there always a solution?\n",
|
||||
" * Yes\n",
|
||||
"* Is the array an array of ints?\n",
|
||||
" * Yes\n",
|
||||
"* Is the array sorted?\n",
|
||||
" No\n",
|
||||
"* Are negative values possible?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None input -> TypeError\n",
|
||||
"* [] -> ValueError\n",
|
||||
"* [1, 3, 2, -7, 5], 7 -> [2, 4]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"### Brute force\n",
|
||||
"\n",
|
||||
"* For i in range(len(input)):\n",
|
||||
" * For j in range(i+1, len(input)):\n",
|
||||
" * if i + j == target return True\n",
|
||||
"* return False\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n^2)\n",
|
||||
"* Space: O(1)\n",
|
||||
"\n",
|
||||
"### Optimized\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"* Loop through each num in nums\n",
|
||||
" * Calculate the cache_target = target - num\n",
|
||||
"\n",
|
||||
"target = 7\n",
|
||||
"index = 0 1 2 3 4\n",
|
||||
"nums = [1, 3, 2, -7, 5]\n",
|
||||
" ^\n",
|
||||
"cache_target = 7 - 1 = 6\n",
|
||||
"cache\n",
|
||||
"6 -> 0\n",
|
||||
"\n",
|
||||
"1 not in cache\n",
|
||||
"\n",
|
||||
"index = 0 1 2 3 4\n",
|
||||
"nums = [1, 3, 2, -7, 5]\n",
|
||||
" ^\n",
|
||||
"cache_target = 7 - 3 = 4\n",
|
||||
"cache\n",
|
||||
"6 -> 0\n",
|
||||
"4 -> 1\n",
|
||||
"\n",
|
||||
"3 not in cache\n",
|
||||
"\n",
|
||||
"index = 0 1 2 3 4\n",
|
||||
"nums = [1, 3, 2, -7, 5]\n",
|
||||
" ^\n",
|
||||
"cache_target = 7 - 2 = 5\n",
|
||||
"cache\n",
|
||||
"6 -> 0\n",
|
||||
"4 -> 1\n",
|
||||
"5 -> 2\n",
|
||||
"\n",
|
||||
"2 not in cache\n",
|
||||
"\n",
|
||||
"index = 0 1 2 3 4\n",
|
||||
"nums = [1, 3, 2, -7, 5]\n",
|
||||
" ^\n",
|
||||
"cache_target = 7 + 7 = 14\n",
|
||||
"cache\n",
|
||||
"6 -> 0\n",
|
||||
"4 -> 1\n",
|
||||
"5 -> 2\n",
|
||||
"14 -> 3\n",
|
||||
"\n",
|
||||
"-7 not in cache\n",
|
||||
"\n",
|
||||
"index = 0 1 2 3 4\n",
|
||||
"nums = [1, 3, 2, -7, 5]\n",
|
||||
" ^\n",
|
||||
"cache_target = 7 - 5 = 2\n",
|
||||
"cache\n",
|
||||
"6 -> 0\n",
|
||||
"4 -> 1\n",
|
||||
"5 -> 2\n",
|
||||
"14 -> 3\n",
|
||||
"\n",
|
||||
"5 in cache, success, output matching indices: cache[num] and current iteration index\n",
|
||||
"\n",
|
||||
"output = [2, 4]\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(n)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def two_sum(self, nums, target):\n",
|
||||
" if nums is None or target is None:\n",
|
||||
" raise TypeError('nums or target cannot be None')\n",
|
||||
" if not nums:\n",
|
||||
" raise ValueError('nums cannot be empty')\n",
|
||||
" cache = {}\n",
|
||||
" for index, num in enumerate(nums):\n",
|
||||
" cache_target = target - num\n",
|
||||
" if num in cache:\n",
|
||||
" return [cache[num], index]\n",
|
||||
" else:\n",
|
||||
" cache[cache_target] = index\n",
|
||||
" return None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_two_sum.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_two_sum.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestTwoSum(object):\n",
|
||||
"\n",
|
||||
" def test_two_sum(self):\n",
|
||||
" solution = Solution()\n",
|
||||
" assert_raises(TypeError, solution.two_sum, None, None)\n",
|
||||
" assert_raises(ValueError, solution.two_sum, [], 0)\n",
|
||||
" target = 7\n",
|
||||
" nums = [1, 3, 2, -7, 5]\n",
|
||||
" expected = [2, 4]\n",
|
||||
" assert_equal(solution.two_sum(nums, target), expected)\n",
|
||||
" print('Success: test_two_sum')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestTwoSum()\n",
|
||||
" test.test_two_sum()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_two_sum\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_two_sum.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
0
bit_manipulation/__init__.py
Normal file
0
bit_manipulation/__init__.py
Normal file
0
bit_manipulation/bit/__init__.py
Normal file
0
bit_manipulation/bit/__init__.py
Normal file
225
bit_manipulation/bit/bit_challenge.ipynb
Normal file
225
bit_manipulation/bit/bit_challenge.ipynb
Normal file
@ -0,0 +1,225 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement common bit manipulation operations: get_bit, set_bit, clear_bit, clear_bits_msb_to_index, clear_bits_msb_to_lsb, update_bit.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None as a number input -> Exception\n",
|
||||
"* Negative index -> Exception\n",
|
||||
"\n",
|
||||
"### get_bit\n",
|
||||
" number = 0b10001110, index = 3\n",
|
||||
" expected = True\n",
|
||||
"### set_bit\n",
|
||||
" number = 0b10001110, index = 4\n",
|
||||
" expected = 0b10011110\n",
|
||||
"### clear_bit\n",
|
||||
" number = 0b10001110, index = 3\n",
|
||||
" expected = 0b10000110\n",
|
||||
"### clear_bits_msb_to_index\n",
|
||||
" number = 0b10001110, index = 3\n",
|
||||
" expected = 0b00000110\n",
|
||||
"### clear_bits_index_to_lsb\n",
|
||||
" number = 0b10001110, index = 3\n",
|
||||
" expected = 0b10000000\n",
|
||||
"### update_bit\n",
|
||||
" number = 0b10001110, index = 3, value = 1\n",
|
||||
" expected = 0b10001110\n",
|
||||
" number = 0b10001110, index = 3, value = 0\n",
|
||||
" expected = 0b10000110\n",
|
||||
" number = 0b10001110, index = 0, value = 1\n",
|
||||
" expected = 0b10001111"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bit(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, number):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def get_bit(self, index):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def set_bit(self, index):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def clear_bit(self, index):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def clear_bits_msb_to_index(self, index):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def clear_bits_index_to_lsb(self, index):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def update_bit(self, index, value):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_bit.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBit(object):\n",
|
||||
"\n",
|
||||
" def test_bit(self):\n",
|
||||
" number = int('10001110', base=2)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" assert_equal(bit.get_bit(index=3), True)\n",
|
||||
" expected = int('10011110', base=2)\n",
|
||||
" assert_equal(bit.set_bit(index=4), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('10000110', base=2)\n",
|
||||
" assert_equal(bit.clear_bit(index=3), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('00000110', base=2)\n",
|
||||
" assert_equal(bit.clear_bits_msb_to_index(index=3), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('10000000', base=2)\n",
|
||||
" assert_equal(bit.clear_bits_index_to_lsb(index=3), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" assert_equal(bit.update_bit(index=3, value=1), number)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('10000110', base=2)\n",
|
||||
" assert_equal(bit.update_bit(index=3, value=0), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('10001111', base=2)\n",
|
||||
" assert_equal(bit.update_bit(index=0, value=1), expected)\n",
|
||||
" print('Success: test_bit')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBit()\n",
|
||||
" test.test_bit()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
358
bit_manipulation/bit/bit_solution.ipynb
Normal file
358
bit_manipulation/bit/bit_solution.ipynb
Normal file
@ -0,0 +1,358 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement common bit manipulation operations: get_bit, set_bit, clear_bit, clear_bits_msb_to_index, clear_bits_msb_to_lsb, update_bit.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None as a number input -> Exception\n",
|
||||
"* Negative index -> Exception\n",
|
||||
"\n",
|
||||
"### get_bit\n",
|
||||
" number = 0b10001110, index = 3\n",
|
||||
" expected = True\n",
|
||||
"### set_bit\n",
|
||||
" number = 0b10001110, index = 4\n",
|
||||
" expected = 0b10011110\n",
|
||||
"### clear_bit\n",
|
||||
" number = 0b10001110, index = 3\n",
|
||||
" expected = 0b10000110\n",
|
||||
"### clear_bits_msb_to_index\n",
|
||||
" number = 0b10001110, index = 3\n",
|
||||
" expected = 0b00000110\n",
|
||||
"### clear_bits_index_to_lsb\n",
|
||||
" number = 0b10001110, index = 3\n",
|
||||
" expected = 0b10000000\n",
|
||||
"### update_bit\n",
|
||||
" number = 0b10001110, index = 3, value = 1\n",
|
||||
" expected = 0b10001110\n",
|
||||
" number = 0b10001110, index = 3, value = 0\n",
|
||||
" expected = 0b10000110\n",
|
||||
" number = 0b10001110, index = 0, value = 1\n",
|
||||
" expected = 0b10001111"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"### get_bit\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"indices 7 6 5 4 3 2 1 0 index = 3\n",
|
||||
"--------------------------------------------------\n",
|
||||
"input 1 0 0 0 1 1 1 0 0b10001110\n",
|
||||
"mask 0 0 0 0 1 0 0 0 1 << index\n",
|
||||
"--------------------------------------------------\n",
|
||||
"result 0 0 0 0 1 0 0 0 number & mask != 0\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(n)\n",
|
||||
"\n",
|
||||
"### set_bit\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"indices 7 6 5 4 3 2 1 0 index = 4\n",
|
||||
"--------------------------------------------------\n",
|
||||
"input 1 0 0 0 1 1 1 0 0b10001110\n",
|
||||
"mask 0 0 0 1 0 0 0 0 1 << index\n",
|
||||
"--------------------------------------------------\n",
|
||||
"result 1 0 0 1 1 1 1 0 number | mask\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(n)\n",
|
||||
"\n",
|
||||
"### clear_bit\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"indices 7 6 5 4 3 2 1 0 index = 3\n",
|
||||
"--------------------------------------------------\n",
|
||||
"input 1 0 0 0 1 1 1 0 0b10001110\n",
|
||||
"mask 0 0 0 0 1 0 0 0 1 << index\n",
|
||||
"mask 1 1 1 1 0 1 1 1 ~(1 << index)\n",
|
||||
"--------------------------------------------------\n",
|
||||
"result 1 0 0 0 0 1 1 0 number & mask\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(n)\n",
|
||||
"\n",
|
||||
"### clear_bits_msb_to_index\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"indices 7 6 5 4 3 2 1 0 index = 3\n",
|
||||
"--------------------------------------------------\n",
|
||||
"input 1 0 0 0 1 1 1 0 0b10001110\n",
|
||||
"mask 0 0 0 0 1 0 0 0 1 << index\n",
|
||||
"mask 0 0 0 0 0 1 1 1 (1 << index) - 1\n",
|
||||
"--------------------------------------------------\n",
|
||||
"result 0 0 0 0 0 1 1 1 number & mask\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(n)\n",
|
||||
"\n",
|
||||
"### clear_bits_index_to_lsb\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"indices 7 6 5 4 3 2 1 0 index = 3\n",
|
||||
"--------------------------------------------------\n",
|
||||
"input 1 0 0 0 1 1 1 0 0b10001110\n",
|
||||
"mask 0 0 0 1 0 0 0 0 1 << index + 1\n",
|
||||
"mask 0 0 0 0 1 1 1 1 (1 << index + 1) - 1\n",
|
||||
"mask 1 1 1 1 0 0 0 0 ~((1 << index + 1) - 1)\n",
|
||||
"--------------------------------------------------\n",
|
||||
"result 1 0 0 0 0 0 0 0 number & mask\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(n)\n",
|
||||
"\n",
|
||||
"### update_bit\n",
|
||||
"\n",
|
||||
"* Use `get_bit` to see if the value is already set or cleared\n",
|
||||
"* If not, use `set_bit` if setting the value or `clear_bit` if clearing the value\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(n)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def validate_index(func):\n",
|
||||
" def validate_index_wrapper(self, *args, **kwargs):\n",
|
||||
" for arg in args:\n",
|
||||
" if arg < 0:\n",
|
||||
" raise IndexError('Invalid index')\n",
|
||||
" return func(self, *args, **kwargs)\n",
|
||||
" return validate_index_wrapper"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bit(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, number):\n",
|
||||
" if number is None:\n",
|
||||
" raise TypeError('number cannot be None')\n",
|
||||
" self.number = number\n",
|
||||
"\n",
|
||||
" @validate_index\n",
|
||||
" def get_bit(self, index):\n",
|
||||
" mask = 1 << index\n",
|
||||
" return self.number & mask != 0\n",
|
||||
"\n",
|
||||
" @validate_index\n",
|
||||
" def set_bit(self, index):\n",
|
||||
" mask = 1 << index\n",
|
||||
" self.number |= mask\n",
|
||||
" return self.number\n",
|
||||
"\n",
|
||||
" @validate_index\n",
|
||||
" def clear_bit(self, index):\n",
|
||||
" mask = ~(1 << index)\n",
|
||||
" self.number &= mask\n",
|
||||
" return self.number\n",
|
||||
"\n",
|
||||
" @validate_index\n",
|
||||
" def clear_bits_msb_to_index(self, index):\n",
|
||||
" mask = (1 << index) - 1\n",
|
||||
" self.number &= mask\n",
|
||||
" return self.number\n",
|
||||
"\n",
|
||||
" @validate_index\n",
|
||||
" def clear_bits_index_to_lsb(self, index):\n",
|
||||
" mask = ~((1 << index + 1) - 1)\n",
|
||||
" self.number &= mask\n",
|
||||
" return self.number\n",
|
||||
"\n",
|
||||
" @validate_index\n",
|
||||
" def update_bit(self, index, value):\n",
|
||||
" if value is None or value not in (0, 1):\n",
|
||||
" raise Exception('Invalid value')\n",
|
||||
" if self.get_bit(index) == value:\n",
|
||||
" return self.number\n",
|
||||
" if value:\n",
|
||||
" self.set_bit(index)\n",
|
||||
" else:\n",
|
||||
" self.clear_bit(index)\n",
|
||||
" return self.number"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_bit.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_bit.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBit(object):\n",
|
||||
"\n",
|
||||
" def test_bit(self):\n",
|
||||
" number = int('10001110', base=2)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" assert_equal(bit.get_bit(index=3), True)\n",
|
||||
" expected = int('10011110', base=2)\n",
|
||||
" assert_equal(bit.set_bit(index=4), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('10000110', base=2)\n",
|
||||
" assert_equal(bit.clear_bit(index=3), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('00000110', base=2)\n",
|
||||
" assert_equal(bit.clear_bits_msb_to_index(index=3), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('10000000', base=2)\n",
|
||||
" assert_equal(bit.clear_bits_index_to_lsb(index=3), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" assert_equal(bit.update_bit(index=3, value=1), number)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('10000110', base=2)\n",
|
||||
" assert_equal(bit.update_bit(index=3, value=0), expected)\n",
|
||||
" bit = Bit(number)\n",
|
||||
" expected = int('10001111', base=2)\n",
|
||||
" assert_equal(bit.update_bit(index=0, value=1), expected)\n",
|
||||
" print('Success: test_bit')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBit()\n",
|
||||
" test.test_bit()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_bit\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_bit.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
38
bit_manipulation/bit/test_bit.py
Normal file
38
bit_manipulation/bit/test_bit.py
Normal file
@ -0,0 +1,38 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestBit(object):
|
||||
|
||||
def test_bit(self):
|
||||
number = int('10001110', base=2)
|
||||
bit = Bit(number)
|
||||
assert_equal(bit.get_bit(index=3), True)
|
||||
expected = int('10011110', base=2)
|
||||
assert_equal(bit.set_bit(index=4), expected)
|
||||
bit = Bit(number)
|
||||
expected = int('10000110', base=2)
|
||||
assert_equal(bit.clear_bit(index=3), expected)
|
||||
bit = Bit(number)
|
||||
expected = int('00000110', base=2)
|
||||
assert_equal(bit.clear_bits_msb_to_index(index=3), expected)
|
||||
bit = Bit(number)
|
||||
expected = int('10000000', base=2)
|
||||
assert_equal(bit.clear_bits_index_to_lsb(index=3), expected)
|
||||
bit = Bit(number)
|
||||
assert_equal(bit.update_bit(index=3, value=1), number)
|
||||
bit = Bit(number)
|
||||
expected = int('10000110', base=2)
|
||||
assert_equal(bit.update_bit(index=3, value=0), expected)
|
||||
bit = Bit(number)
|
||||
expected = int('10001111', base=2)
|
||||
assert_equal(bit.update_bit(index=0, value=1), expected)
|
||||
print('Success: test_bit')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestBit()
|
||||
test.test_bit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
bit_manipulation/bits_to_flip/__init__.py
Normal file
0
bit_manipulation/bits_to_flip/__init__.py
Normal file
172
bit_manipulation/bits_to_flip/bits_to_flip_challenge.ipynb
Normal file
172
bit_manipulation/bits_to_flip/bits_to_flip_challenge.ipynb
Normal file
@ -0,0 +1,172 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Determine the number of bits to flip to convert int a to int b'.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume A and B are always ints?\n",
|
||||
" * Yes\n",
|
||||
"* Is the output an int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume A and B are always the same number of bits?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid (not None)?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* A or B is None -> Exception\n",
|
||||
"* General case\n",
|
||||
"<pre>\n",
|
||||
" A = 11101\n",
|
||||
" B = 01111\n",
|
||||
" Result: 2\n",
|
||||
"<pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def bits_to_flip(self, a, b):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_bits_to_flip.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_bits_to_flip(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" a = int('11101', base=2)\n",
|
||||
" b = int('01111', base=2)\n",
|
||||
" expected = 2\n",
|
||||
" assert_equal(bits.bits_to_flip(a, b), expected)\n",
|
||||
" print('Success: test_bits_to_flip')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_bits_to_flip()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
200
bit_manipulation/bits_to_flip/bits_to_flip_solution.ipynb
Normal file
200
bit_manipulation/bits_to_flip/bits_to_flip_solution.ipynb
Normal file
@ -0,0 +1,200 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Determine the number of bits to flip to convert int a to int b.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume A and B are always ints?\n",
|
||||
" * Yes\n",
|
||||
"* Is the output an int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume A and B are always the same number of bits?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid (not None)?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* A or B is None -> Exception\n",
|
||||
"* General case\n",
|
||||
"<pre>\n",
|
||||
" A = 11101\n",
|
||||
" B = 01111\n",
|
||||
" Result: 2\n",
|
||||
"<pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"We can use the xor operator to determine the bit differences between a and b\n",
|
||||
"\n",
|
||||
"* Set count to 0\n",
|
||||
"* Set c to a xor b\n",
|
||||
"* Loop while c != 0:\n",
|
||||
" * Increment count if the LSB in c is a 1\n",
|
||||
" * We can check this by using a mask of 1\n",
|
||||
" * Right shift c by 1\n",
|
||||
"* Return the count\n",
|
||||
" \n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(b), where b is the number of bits\n",
|
||||
"* Space: O(b), where b is the number of bits"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def bits_to_flip(self, a, b):\n",
|
||||
" if a is None or b is None:\n",
|
||||
" raise TypeError('a or b cannot be None')\n",
|
||||
" count = 0\n",
|
||||
" c = a ^ b\n",
|
||||
" while c:\n",
|
||||
" count += c & 1\n",
|
||||
" c >>= 1\n",
|
||||
" return count"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_bits_to_flip.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_bits_to_flip.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_bits_to_flip(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" a = int('11101', base=2)\n",
|
||||
" b = int('01111', base=2)\n",
|
||||
" expected = 2\n",
|
||||
" assert_equal(bits.bits_to_flip(a, b), expected)\n",
|
||||
" print('Success: test_bits_to_flip')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_bits_to_flip()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_bits_to_flip\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_bits_to_flip.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
21
bit_manipulation/bits_to_flip/test_bits_to_flip.py
Normal file
21
bit_manipulation/bits_to_flip/test_bits_to_flip.py
Normal file
@ -0,0 +1,21 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestBits(object):
|
||||
|
||||
def test_bits_to_flip(self):
|
||||
bits = Bits()
|
||||
a = int('11101', base=2)
|
||||
b = int('01111', base=2)
|
||||
expected = 2
|
||||
assert_equal(bits.bits_to_flip(a, b), expected)
|
||||
print('Success: test_bits_to_flip')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestBits()
|
||||
test.test_bits_to_flip()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
bit_manipulation/draw_line/__init__.py
Normal file
0
bit_manipulation/draw_line/__init__.py
Normal file
180
bit_manipulation/draw_line/draw_line_challenge.ipynb
Normal file
180
bit_manipulation/draw_line/draw_line_challenge.ipynb
Normal file
@ -0,0 +1,180 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement the method draw_line(screen, width, x1, x2) where screen is a list of bytes, width is divisible by 8, and x1, x2 are absolute pixel positions.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* For the output, do we set corresponding bits in screen?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* Invalid inputs -> Exception\n",
|
||||
" * screen is empty\n",
|
||||
" * width = 0\n",
|
||||
" * any input param is None\n",
|
||||
" * x1 or x2 is out of bounds\n",
|
||||
"* General case for len(screen) = 20, width = 32:\n",
|
||||
" * x1 = 2, x2 = 6\n",
|
||||
" * screen[0] = int('00111110', base=2)\n",
|
||||
" * x1 = 68, x2 = 80\n",
|
||||
" * screen[8], int('00001111', base=2)\n",
|
||||
" * screen[9], int('11111111', base=2)\n",
|
||||
" * screen[10], int('10000000', base=2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class BitsScreen(object):\n",
|
||||
"\n",
|
||||
" def draw_line(self, screen, width, x1, x2):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_draw_line.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBitsScreen(object):\n",
|
||||
"\n",
|
||||
" def test_draw_line(self):\n",
|
||||
" bits_screen = BitsScreen()\n",
|
||||
" screen = []\n",
|
||||
" for _ in range(20):\n",
|
||||
" screen.append(int('00000000', base=2))\n",
|
||||
" bits_screen.draw_line(screen, width=32, x1=68, x2=80)\n",
|
||||
" assert_equal(screen[8], int('00001111', base=2))\n",
|
||||
" assert_equal(screen[9], int('11111111', base=2))\n",
|
||||
" assert_equal(screen[10], int('10000000', base=2))\n",
|
||||
" bits_screen.draw_line(screen, width=32, x1=2, x2=6)\n",
|
||||
" assert_equal(screen[0], int('00111110', base=2))\n",
|
||||
" bits_screen.draw_line(screen, width=32, x1=10, x2=13)\n",
|
||||
" assert_equal(screen[1], int('00111100', base=2))\n",
|
||||
" print('Success: test_draw_line')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBitsScreen()\n",
|
||||
" test.test_draw_line()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
288
bit_manipulation/draw_line/draw_line_solution.ipynb
Normal file
288
bit_manipulation/draw_line/draw_line_solution.ipynb
Normal file
@ -0,0 +1,288 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement the method draw_line(screen, width, x1, x2) where screen is a list of bytes, width is divisible by 8, and x1, x2 are absolute pixel positions.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* For the output, do we set corresponding bits in screen?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* Invalid inputs -> Exception\n",
|
||||
" * screen is empty\n",
|
||||
" * width = 0\n",
|
||||
" * any input param is None\n",
|
||||
" * x1 or x2 is out of bounds\n",
|
||||
"* General case for len(screen) = 20, width = 32:\n",
|
||||
" * x1 = 2, x2 = 6\n",
|
||||
" * screen[0] = int('00111110', base=2)\n",
|
||||
" * x1 = 68, x2 = 80\n",
|
||||
" * screen[8], int('00001111', base=2)\n",
|
||||
" * screen[9], int('11111111', base=2)\n",
|
||||
" * screen[10], int('10000000', base=2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"* Set start offset to x1 % 8\n",
|
||||
"* Set end offset to x2 % 8\n",
|
||||
"* Determine where the first and last full bytes are\n",
|
||||
" * First full byte = x1 // 8\n",
|
||||
" * Increment by 1 if start offset != 0\n",
|
||||
" * Last full byte = x2 // 8\n",
|
||||
" * Decrement by 1 if end offset != 7\n",
|
||||
" * Fill the bytes with 1111 1111\n",
|
||||
"* If x1 and x2 are in the same byte\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" x1 = 2\n",
|
||||
" x2 = 6\n",
|
||||
"\n",
|
||||
" index 0123 4567\n",
|
||||
" byte 0011 1110\n",
|
||||
"\n",
|
||||
" We want to build left and right masks such that:\n",
|
||||
"\n",
|
||||
" left 0011 1111\n",
|
||||
" right 1111 1110\n",
|
||||
" ----------------\n",
|
||||
" 0011 1110 left & right\n",
|
||||
"\n",
|
||||
" Build the left mask:\n",
|
||||
"\n",
|
||||
" left 0000 0001 1\n",
|
||||
" 0100 0000 1 << (8 - x1)\n",
|
||||
" 0011 1111 (1 << (8 - x1)) - 1\n",
|
||||
"\n",
|
||||
" Build the right mask:\n",
|
||||
"\n",
|
||||
" right 0000 0000 1\n",
|
||||
" 0000 0010 1 << (8 - x2 - 1)\n",
|
||||
" 0000 0001 (1 << (8 - x2 - 1) - 1\n",
|
||||
" 1111 1110 ~((1 << (8 - x2 - 1) - 1)\n",
|
||||
"\n",
|
||||
" Combine the left and right masks:\n",
|
||||
"\n",
|
||||
" left 0011 1111\n",
|
||||
" right 1111 1110\n",
|
||||
" ----------------\n",
|
||||
" 0011 1110 left & right\n",
|
||||
"\n",
|
||||
" Set screen[x1//8] or screen[x2//8] |= mask\n",
|
||||
"</pre>\n",
|
||||
"* Else\n",
|
||||
"<pre>\n",
|
||||
" If our starting partial byte is:\n",
|
||||
" 0000 1111\n",
|
||||
"\n",
|
||||
" Build start mask:\n",
|
||||
" \n",
|
||||
" start 0000 0001 1\n",
|
||||
" 0001 0000 1 << 1 << start offset\n",
|
||||
" 0000 1111 (1 << 1 << start offset) - 1\n",
|
||||
"\n",
|
||||
" If our ending partial byte is:\n",
|
||||
" 1111 1100\n",
|
||||
"\n",
|
||||
" Build end mask:\n",
|
||||
" \n",
|
||||
" end 1000 0000 0x10000000\n",
|
||||
" 1111 1100 0x10000000 >> end offset\n",
|
||||
"\n",
|
||||
" Set screen[x1//8] |= start mask\n",
|
||||
" Set screen[x2//8] |= end mask\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(length of screen)\n",
|
||||
"* Space: O(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class BitsScreen(object):\n",
|
||||
"\n",
|
||||
" def draw_line(self, screen, width, x1, x2):\n",
|
||||
" if None in (screen, width, x1, x2):\n",
|
||||
" raise TypeError('Invalid argument: None')\n",
|
||||
" if not screen or not width:\n",
|
||||
" raise ValueError('Invalid arg: Empty screen or width')\n",
|
||||
" MAX_BIT_VALUE = len(screen) * 8\n",
|
||||
" if x1 < 0 or x2 < 0 or x1 >= MAX_BIT_VALUE or x2 >= MAX_BIT_VALUE:\n",
|
||||
" raise ValueError('Invalid arg: x1 or x2 out of bounds')\n",
|
||||
" start_bit = x1 % 8\n",
|
||||
" end_bit = x2 % 8\n",
|
||||
" first_full_byte = x1 // 8\n",
|
||||
" if start_bit != 0:\n",
|
||||
" first_full_byte += 1\n",
|
||||
" last_full_byte = x2 // 8\n",
|
||||
" if end_bit != (8 - 1):\n",
|
||||
" last_full_byte -= 1\n",
|
||||
" for byte in range(first_full_byte, last_full_byte + 1):\n",
|
||||
" screen[byte] = int('11111111', base=2)\n",
|
||||
" start_byte = x1 // 8\n",
|
||||
" end_byte = x2 // 8\n",
|
||||
" if start_byte == end_byte:\n",
|
||||
" left_mask = (1 << (8 - start_bit)) - 1\n",
|
||||
" right_mask = ~((1 << (8 - end_bit - 1)) - 1)\n",
|
||||
" mask = left_mask & right_mask\n",
|
||||
" screen[start_byte] |= mask\n",
|
||||
" else:\n",
|
||||
" start_mask = (1 << (8 - start_bit)) - 1\n",
|
||||
" end_mask = 1 << (8 - end_bit - 1)\n",
|
||||
" screen[start_byte] |= start_mask\n",
|
||||
" screen[end_byte] |= end_mask"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_draw_line.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_draw_line.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBitsScreen(object):\n",
|
||||
"\n",
|
||||
" def test_draw_line(self):\n",
|
||||
" bits_screen = BitsScreen()\n",
|
||||
" screen = []\n",
|
||||
" for _ in range(20):\n",
|
||||
" screen.append(int('00000000', base=2))\n",
|
||||
" bits_screen.draw_line(screen, width=32, x1=68, x2=80)\n",
|
||||
" assert_equal(screen[8], int('00001111', base=2))\n",
|
||||
" assert_equal(screen[9], int('11111111', base=2))\n",
|
||||
" assert_equal(screen[10], int('10000000', base=2))\n",
|
||||
" bits_screen.draw_line(screen, width=32, x1=2, x2=6)\n",
|
||||
" assert_equal(screen[0], int('00111110', base=2))\n",
|
||||
" bits_screen.draw_line(screen, width=32, x1=10, x2=13)\n",
|
||||
" assert_equal(screen[1], int('00111100', base=2))\n",
|
||||
" print('Success: test_draw_line')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBitsScreen()\n",
|
||||
" test.test_draw_line()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_draw_line\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_draw_line.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
28
bit_manipulation/draw_line/test_draw_line.py
Normal file
28
bit_manipulation/draw_line/test_draw_line.py
Normal file
@ -0,0 +1,28 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestBitsScreen(object):
|
||||
|
||||
def test_draw_line(self):
|
||||
bits_screen = BitsScreen()
|
||||
screen = []
|
||||
for _ in range(20):
|
||||
screen.append(int('00000000', base=2))
|
||||
bits_screen.draw_line(screen, width=32, x1=68, x2=80)
|
||||
assert_equal(screen[8], int('00001111', base=2))
|
||||
assert_equal(screen[9], int('11111111', base=2))
|
||||
assert_equal(screen[10], int('10000000', base=2))
|
||||
bits_screen.draw_line(screen, width=32, x1=2, x2=6)
|
||||
assert_equal(screen[0], int('00111110', base=2))
|
||||
bits_screen.draw_line(screen, width=32, x1=10, x2=13)
|
||||
assert_equal(screen[1], int('00111100', base=2))
|
||||
print('Success: test_draw_line')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestBitsScreen()
|
||||
test.test_draw_line()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
bit_manipulation/flip_bit/__init__.py
Normal file
0
bit_manipulation/flip_bit/__init__.py
Normal file
182
bit_manipulation/flip_bit/flip_bit_challenge.ipynb
Normal file
182
bit_manipulation/flip_bit/flip_bit_challenge.ipynb
Normal file
@ -0,0 +1,182 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Flip one bit from 0 to 1 to maximize the longest sequence of 1s.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the input an int, base 2?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the input is a 32 bit number?\n",
|
||||
" * Yes\n",
|
||||
"* Do we have to validate the length of the input?\n",
|
||||
" * No\n",
|
||||
"* Is the output an int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume we are using a positive number since Python doesn't have an >>> operator?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> Exception\n",
|
||||
"* All 1's -> Count of 1s\n",
|
||||
"* All 0's -> 1\n",
|
||||
"* General case\n",
|
||||
" * 0000 1111 1101 1101 1111 0011 1111 0000 -> 10 (ten)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def flip_bit(self, num):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_flip_bit.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_flip_bit(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_raises(TypeError, bits.flip_bit, None)\n",
|
||||
" assert_equal(bits.flip_bit(0), 1)\n",
|
||||
" assert_equal(bits.flip_bit(-1), bits.MAX_BITS)\n",
|
||||
" num = int('00001111110111011110001111110000', base=2)\n",
|
||||
" expected = 10\n",
|
||||
" assert_equal(bits.flip_bit(num), expected)\n",
|
||||
" num = int('00000100111011101111100011111011', base=2)\n",
|
||||
" expected = 9\n",
|
||||
" assert_equal(bits.flip_bit(num), expected)\n",
|
||||
" num = int('00010011101110111110001111101111', base=2)\n",
|
||||
" expected = 10\n",
|
||||
" assert_equal(bits.flip_bit(num), expected)\n",
|
||||
" print('Success: test_print_binary')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_flip_bit()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
275
bit_manipulation/flip_bit/flip_bit_solution.ipynb
Normal file
275
bit_manipulation/flip_bit/flip_bit_solution.ipynb
Normal file
@ -0,0 +1,275 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Flip one bit from 0 to 1 to maximize the longest sequence of 1s.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the input an int, base 2?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the input is a 32 bit number?\n",
|
||||
" * Yes\n",
|
||||
"* Do we have to validate the length of the input?\n",
|
||||
" * No\n",
|
||||
"* Is the output an int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume we are using a positive number since Python doesn't have an >>> operator?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> Exception\n",
|
||||
"* All 1's -> Count of 1s\n",
|
||||
"* All 0's -> 1\n",
|
||||
"* General case\n",
|
||||
" * Trailing zeroes\n",
|
||||
" * 0000 1111 1101 1101 1111 0011 1111 0000 -> 10 (ten)\n",
|
||||
" * Trailing ones\n",
|
||||
" * 0000 1001 1101 1101 1111 0001 1111 0111 -> 9"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"* seen = []\n",
|
||||
"* Build a list of sequence counts\n",
|
||||
" * Look for 0's\n",
|
||||
" * This will be 0 length if the input has trailing ones\n",
|
||||
" * Add sequence length to seen\n",
|
||||
" * Look for 1's\n",
|
||||
" * Add sequence length to seen\n",
|
||||
"* Find the largest sequence of ones looking at seen\n",
|
||||
" * Loop through seen\n",
|
||||
" * On each iteration of the loop, flip what we are looking for from 0 to 1 and vice versa\n",
|
||||
" * If seen[i] represents 1's, continue, we only want to process 0's\n",
|
||||
" * If this is our first iteration:\n",
|
||||
" * max_result = seen[i+1] + 1 if seen[i] > 0\n",
|
||||
" * continue\n",
|
||||
" * If we are looking at leading zeroes (i == len(seen)-1):\n",
|
||||
" * result = seen[i-1] + 1\n",
|
||||
" * If we are looking at one zero:\n",
|
||||
" * result = seen[i+1] + seen[i-1] + 1\n",
|
||||
" * If we are looking at multiple zeroes:\n",
|
||||
" * result = max(seen[i+1], seen[i-1]) + 1\n",
|
||||
" * Update max_result based on result\n",
|
||||
"\n",
|
||||
"We should make a note that Python does not have a logical right shift operator built in. We can either use a positive number or implement one for a 32 bit number:\n",
|
||||
"\n",
|
||||
" num % 0x100000000 >> n\n",
|
||||
" \n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(b)\n",
|
||||
"* Space: O(b)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" MAX_BITS = 32\n",
|
||||
" \n",
|
||||
" def _build_seen_list(self, num):\n",
|
||||
" seen = []\n",
|
||||
" looking_for = 0\n",
|
||||
" count = 0\n",
|
||||
" for _ in range(self.MAX_BITS):\n",
|
||||
" if num & 1 != looking_for:\n",
|
||||
" seen.append(count)\n",
|
||||
" looking_for = not looking_for\n",
|
||||
" count = 0\n",
|
||||
" count += 1\n",
|
||||
" num >>= 1\n",
|
||||
" seen.append(count)\n",
|
||||
" return seen\n",
|
||||
" \n",
|
||||
" def flip_bit(self, num):\n",
|
||||
" if num is None:\n",
|
||||
" raise TypeError('num cannot be None')\n",
|
||||
" if num == -1:\n",
|
||||
" return self.MAX_BITS\n",
|
||||
" if num == 0:\n",
|
||||
" return 1\n",
|
||||
" seen = self._build_seen_list(num)\n",
|
||||
" max_result = 0\n",
|
||||
" looking_for = 0\n",
|
||||
" for index, count in enumerate(seen):\n",
|
||||
" result = 0\n",
|
||||
" # Only look for zeroes\n",
|
||||
" if looking_for == 1:\n",
|
||||
" looking_for = not looking_for\n",
|
||||
" continue\n",
|
||||
" # First iteration, take trailing zeroes\n",
|
||||
" # or trailing ones into account\n",
|
||||
" if index == 0:\n",
|
||||
" if count != 0:\n",
|
||||
" # Trailing zeroes\n",
|
||||
" try:\n",
|
||||
" result = seen[index + 1] + 1\n",
|
||||
" except IndexError:\n",
|
||||
" result = 1\n",
|
||||
" # Last iteration\n",
|
||||
" elif index == len(seen) - 1:\n",
|
||||
" result = 1 + seen[index - 1]\n",
|
||||
" else:\n",
|
||||
" # One zero\n",
|
||||
" if count == 1:\n",
|
||||
" result = seen[index + 1] + seen[index - 1] + 1\n",
|
||||
" # Multiple zeroes\n",
|
||||
" else:\n",
|
||||
" result = max(seen[index + 1], seen[index - 1]) + 1\n",
|
||||
" if result > max_result:\n",
|
||||
" max_result = result\n",
|
||||
" looking_for = not looking_for\n",
|
||||
" return max_result"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_flip_bit.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_flip_bit.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_flip_bit(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_raises(TypeError, bits.flip_bit, None)\n",
|
||||
" assert_equal(bits.flip_bit(0), 1)\n",
|
||||
" assert_equal(bits.flip_bit(-1), bits.MAX_BITS)\n",
|
||||
" num = int('00001111110111011110001111110000', base=2)\n",
|
||||
" expected = 10\n",
|
||||
" assert_equal(bits.flip_bit(num), expected)\n",
|
||||
" num = int('00000100111011101111100011111011', base=2)\n",
|
||||
" expected = 9\n",
|
||||
" assert_equal(bits.flip_bit(num), expected)\n",
|
||||
" num = int('00010011101110111110001111101111', base=2)\n",
|
||||
" expected = 10\n",
|
||||
" assert_equal(bits.flip_bit(num), expected)\n",
|
||||
" print('Success: test_print_binary')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_flip_bit()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_print_binary\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_flip_bit.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
29
bit_manipulation/flip_bit/test_flip_bit.py
Normal file
29
bit_manipulation/flip_bit/test_flip_bit.py
Normal file
@ -0,0 +1,29 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestBits(object):
|
||||
|
||||
def test_flip_bit(self):
|
||||
bits = Bits()
|
||||
assert_raises(TypeError, bits.flip_bit, None)
|
||||
assert_equal(bits.flip_bit(0), 1)
|
||||
assert_equal(bits.flip_bit(-1), bits.MAX_BITS)
|
||||
num = int('00001111110111011110001111110000', base=2)
|
||||
expected = 10
|
||||
assert_equal(bits.flip_bit(num), expected)
|
||||
num = int('00000100111011101111100011111011', base=2)
|
||||
expected = 9
|
||||
assert_equal(bits.flip_bit(num), expected)
|
||||
num = int('00010011101110111110001111101111', base=2)
|
||||
expected = 10
|
||||
assert_equal(bits.flip_bit(num), expected)
|
||||
print('Success: test_print_binary')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestBits()
|
||||
test.test_flip_bit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
bit_manipulation/get_next/__init__.py
Normal file
0
bit_manipulation/get_next/__init__.py
Normal file
186
bit_manipulation/get_next/get_next_challenge.ipynb
Normal file
186
bit_manipulation/get_next/get_next_challenge.ipynb
Normal file
@ -0,0 +1,186 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given a positive integer, get the next largest number and the next smallest number with the same number of 1's as the given number.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the output a positive int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> Exception\n",
|
||||
"* 0 -> Exception\n",
|
||||
"* negative int -> Exception\n",
|
||||
"* General case:\n",
|
||||
"<pre>\n",
|
||||
" * Input: 0000 0000 1101 0111\n",
|
||||
" * Next largest: 0000 0000 1101 1011\n",
|
||||
" * Next smallest: 0000 0000 1100 1111\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def get_next_largest(self, num):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def get_next_smallest(self, num):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_get_next_largest.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_get_next_largest(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_raises(Exception, bits.get_next_largest, None)\n",
|
||||
" assert_raises(Exception, bits.get_next_largest, 0)\n",
|
||||
" assert_raises(Exception, bits.get_next_largest, -1)\n",
|
||||
" num = int('011010111', base=2)\n",
|
||||
" expected = int('011011011', base=2)\n",
|
||||
" assert_equal(bits.get_next_largest(num), expected)\n",
|
||||
" print('Success: test_get_next_largest')\n",
|
||||
"\n",
|
||||
" def test_get_next_smallest(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_raises(Exception, bits.get_next_smallest, None)\n",
|
||||
" assert_raises(Exception, bits.get_next_smallest, 0)\n",
|
||||
" assert_raises(Exception, bits.get_next_smallest, -1)\n",
|
||||
" num = int('011010111', base=2)\n",
|
||||
" expected = int('011001111', base=2)\n",
|
||||
" assert_equal(bits.get_next_smallest(num), expected)\n",
|
||||
" print('Success: test_get_next_smallest')\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_get_next_largest()\n",
|
||||
" test.test_get_next_smallest()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
272
bit_manipulation/get_next/get_next_solution.ipynb
Normal file
272
bit_manipulation/get_next/get_next_solution.ipynb
Normal file
@ -0,0 +1,272 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given a positive integer, get the next largest number and the next smallest number with the same number of 1's as the given number.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the output a positive int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> Exception\n",
|
||||
"* 0 -> Exception\n",
|
||||
"* negative int -> Exception\n",
|
||||
"* General case:\n",
|
||||
"<pre>\n",
|
||||
" * Input: 0000 0000 1101 0111\n",
|
||||
" * Next largest: 0000 0000 1101 1011\n",
|
||||
" * Next smallest: 0000 0000 1100 1111\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"### get_next_largest\n",
|
||||
"\n",
|
||||
"* Find the right-most non trailing zero, call this index\n",
|
||||
" * We'll use a mask of 1 and do a logical right shift on a copy of num to examine each bit starting from the right\n",
|
||||
" * Count the number of zeroes to the right of index\n",
|
||||
" * While num & 1 == 0 and num_copy != 0:\n",
|
||||
" * Increment number of zeroes\n",
|
||||
" * Logical shift right num_copy\n",
|
||||
" * Count the number of ones to the right of index\n",
|
||||
" * While num & 1 == 1 and num_copy != 0:\n",
|
||||
" * Increment number of ones\n",
|
||||
" * Logical shift right num_copy\n",
|
||||
" * The index will be the sum of number of ones and number of zeroes\n",
|
||||
" * Set the index bit\n",
|
||||
" * Clear all bits to the right of index\n",
|
||||
" * Set bits starting from 0\n",
|
||||
" * Only set (number of ones - 1) bits because we set index to 1\n",
|
||||
"\n",
|
||||
"We should make a note that Python does not have a logical right shift operator built in. We can either use a positive number of implement one for a 32 bit number:\n",
|
||||
"\n",
|
||||
" num % 0x100000000 >> n\n",
|
||||
"\n",
|
||||
"### get_next_smallest\n",
|
||||
"\n",
|
||||
"* The algorithm for finding the next smallest number is very similar to finding the next largest number\n",
|
||||
" * Instead of finding the right-most non-trailing zero, we'll find the right most non-trailing one and clear it\n",
|
||||
" * Clear all bits to the right of index\n",
|
||||
" * Set bits starting at 0 to the number of ones to the right of index, plus one\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(b), where b is the number of bits in num\n",
|
||||
"* Space: O(b), where b is the number of bits in num"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def get_next_largest(self, num):\n",
|
||||
" if num is None:\n",
|
||||
" raise TypeError('num cannot be None')\n",
|
||||
" if num <= 0:\n",
|
||||
" raise ValueError('num cannot be 0 or negative')\n",
|
||||
" num_ones = 0\n",
|
||||
" num_zeroes = 0\n",
|
||||
" num_copy = num\n",
|
||||
" # We'll look for index, which is the right-most non-trailing zero\n",
|
||||
" # Count number of zeroes to the right of index\n",
|
||||
" while num_copy != 0 and num_copy & 1 == 0:\n",
|
||||
" num_zeroes += 1\n",
|
||||
" num_copy >>= 1\n",
|
||||
" # Count number of ones to the right of index\n",
|
||||
" while num_copy != 0 and num_copy & 1 == 1:\n",
|
||||
" num_ones += 1\n",
|
||||
" num_copy >>= 1\n",
|
||||
" # Determine index and set the bit\n",
|
||||
" index = num_zeroes + num_ones\n",
|
||||
" num |= 1 << index\n",
|
||||
" # Clear all bits to the right of index\n",
|
||||
" num &= ~((1 << index) - 1)\n",
|
||||
" # Set bits starting from 0\n",
|
||||
" num |= ((1 << num_ones - 1) - 1)\n",
|
||||
" return num\n",
|
||||
"\n",
|
||||
" def get_next_smallest(self, num):\n",
|
||||
" if num is None:\n",
|
||||
" raise TypeError('num cannot be None')\n",
|
||||
" if num <= 0:\n",
|
||||
" raise ValueError('num cannot be 0 or negative')\n",
|
||||
" num_ones = 0\n",
|
||||
" num_zeroes = 0\n",
|
||||
" num_copy = num\n",
|
||||
" # We'll look for index, which is the right-most non-trailing one\n",
|
||||
" # Count number of zeroes to the right of index\n",
|
||||
" while num_copy != 0 and num_copy & 1 == 1:\n",
|
||||
" num_ones += 1\n",
|
||||
" num_copy >>= 1\n",
|
||||
" # Count number of zeroes to the right of index\n",
|
||||
" while num_copy != 0 and num_copy & 1 == 0:\n",
|
||||
" num_zeroes += 1\n",
|
||||
" num_copy >>= 1\n",
|
||||
" # Determine index and clear the bit\n",
|
||||
" index = num_zeroes + num_ones\n",
|
||||
" num &= ~(1 << index)\n",
|
||||
" # Clear all bits to the right of index\n",
|
||||
" num &= ~((1 << index) - 1)\n",
|
||||
" # Set bits starting from 0\n",
|
||||
" num |= (1 << num_ones + 1) - 1\n",
|
||||
" return num"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_get_next_largest.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_get_next_largest.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_get_next_largest(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_raises(Exception, bits.get_next_largest, None)\n",
|
||||
" assert_raises(Exception, bits.get_next_largest, 0)\n",
|
||||
" assert_raises(Exception, bits.get_next_largest, -1)\n",
|
||||
" num = int('011010111', base=2)\n",
|
||||
" expected = int('011011011', base=2)\n",
|
||||
" assert_equal(bits.get_next_largest(num), expected)\n",
|
||||
" print('Success: test_get_next_largest')\n",
|
||||
"\n",
|
||||
" def test_get_next_smallest(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_raises(Exception, bits.get_next_smallest, None)\n",
|
||||
" assert_raises(Exception, bits.get_next_smallest, 0)\n",
|
||||
" assert_raises(Exception, bits.get_next_smallest, -1)\n",
|
||||
" num = int('011010111', base=2)\n",
|
||||
" expected = int('011001111', base=2)\n",
|
||||
" assert_equal(bits.get_next_smallest(num), expected)\n",
|
||||
" print('Success: test_get_next_smallest')\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_get_next_largest()\n",
|
||||
" test.test_get_next_smallest()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_get_next_largest\n",
|
||||
"Success: test_get_next_smallest\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_get_next_largest.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
33
bit_manipulation/get_next/test_get_next_largest.py
Normal file
33
bit_manipulation/get_next/test_get_next_largest.py
Normal file
@ -0,0 +1,33 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestBits(object):
|
||||
|
||||
def test_get_next_largest(self):
|
||||
bits = Bits()
|
||||
assert_raises(Exception, bits.get_next_largest, None)
|
||||
assert_raises(Exception, bits.get_next_largest, 0)
|
||||
assert_raises(Exception, bits.get_next_largest, -1)
|
||||
num = int('011010111', base=2)
|
||||
expected = int('011011011', base=2)
|
||||
assert_equal(bits.get_next_largest(num), expected)
|
||||
print('Success: test_get_next_largest')
|
||||
|
||||
def test_get_next_smallest(self):
|
||||
bits = Bits()
|
||||
assert_raises(Exception, bits.get_next_smallest, None)
|
||||
assert_raises(Exception, bits.get_next_smallest, 0)
|
||||
assert_raises(Exception, bits.get_next_smallest, -1)
|
||||
num = int('011010111', base=2)
|
||||
expected = int('011001111', base=2)
|
||||
assert_equal(bits.get_next_smallest(num), expected)
|
||||
print('Success: test_get_next_smallest')
|
||||
|
||||
def main():
|
||||
test = TestBits()
|
||||
test.test_get_next_largest()
|
||||
test.test_get_next_smallest()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
bit_manipulation/insert_m_into_n/__init__.py
Normal file
0
bit_manipulation/insert_m_into_n/__init__.py
Normal file
173
bit_manipulation/insert_m_into_n/insert_m_into_n_challenge.ipynb
Normal file
173
bit_manipulation/insert_m_into_n/insert_m_into_n_challenge.ipynb
Normal file
@ -0,0 +1,173 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given two 16 bit numbers, n and m, and two indices i, j, insert m into n such that m starts at bit j and ends at bit i.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume j > i?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume i through j have enough space for m?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None as an input -> Exception\n",
|
||||
"* Negative index for i or j -> Exception\n",
|
||||
"* General case\n",
|
||||
"<pre>\n",
|
||||
"i = 2\n",
|
||||
"j = 6\n",
|
||||
"n = 0000 0100 0000 0000\n",
|
||||
"m = 0000 0000 0001 0011\n",
|
||||
"result = 0000 0100 0100 1100\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def insert_m_into_n(self, m, n, i, j):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_insert_m_into_n.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBit(object):\n",
|
||||
"\n",
|
||||
" def test_insert_m_into_n(self):\n",
|
||||
" n = int('0000010000111101', base=2)\n",
|
||||
" m = int('0000000000010011', base=2)\n",
|
||||
" expected = int('0000010001001101', base=2)\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_equal(bits.insert_m_into_n(m, n, i=2, j=6), expected)\n",
|
||||
" print('Success: test_insert_m_into_n')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBit()\n",
|
||||
" test.test_insert_m_into_n()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
221
bit_manipulation/insert_m_into_n/insert_m_into_n_solution.ipynb
Normal file
221
bit_manipulation/insert_m_into_n/insert_m_into_n_solution.ipynb
Normal file
@ -0,0 +1,221 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given two 16 bit numbers, n and m, and two indices i, j, insert m into n such that m starts at bit j and ends at bit i.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume j > i?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume i through j have enough space for m?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None as an input -> Exception\n",
|
||||
"* Negative index for i or j -> Exception\n",
|
||||
"* General case\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"i = 2, j = 6\n",
|
||||
" j i\n",
|
||||
"n = 0000 0100 0011 1101\n",
|
||||
"m = 0000 0000 0001 0011\n",
|
||||
"result = 0000 0100 0100 1101\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" j i\n",
|
||||
"n = 0000 0100 0011 1101\n",
|
||||
"m = 0000 0000 0001 0011\n",
|
||||
"\n",
|
||||
"lmask = 1111 1111 1111 1111 -1\n",
|
||||
"lmask = 1111 1111 1000 0000 -1 << (j + 1)\n",
|
||||
"\n",
|
||||
"rmask = 0000 0000 0000 0001 1\n",
|
||||
"rmask = 0000 0000 0000 0100 1 << i\n",
|
||||
"rmask = 0000 0000 0000 0011 (1 << i) -1\n",
|
||||
"\n",
|
||||
"mask = 1111 1111 1000 0011 lmask | rmask\n",
|
||||
"\n",
|
||||
"n = 0000 0100 0011 1101\n",
|
||||
"mask = 1111 1111 1000 0011 n & mask \n",
|
||||
"--------------------------------------------------\n",
|
||||
"n2 = 0000 0100 0000 0001\n",
|
||||
"\n",
|
||||
"n2 = 0000 0100 0000 0001\n",
|
||||
"mask2 = 0000 0000 0100 1100 m << i\n",
|
||||
"--------------------------------------------------\n",
|
||||
"result = 0000 0100 0100 1101 n2 | mask2\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(b), where b is the number of bits\n",
|
||||
"* Space: O(b), where b is the number of bits"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def insert_m_into_n(self, m, n, i, j):\n",
|
||||
" if None in (m, n, i, j):\n",
|
||||
" raise TypeError('Argument cannot be None')\n",
|
||||
" if i < 0 or j < 0:\n",
|
||||
" raise ValueError('Index cannot be negative')\n",
|
||||
" left_mask = -1 << (j + 1)\n",
|
||||
" right_mask = (1 << i) - 1\n",
|
||||
" n_mask = left_mask | right_mask\n",
|
||||
" # Clear bits from j to i, inclusive\n",
|
||||
" n_cleared = n & n_mask\n",
|
||||
" # Shift m into place before inserting it into n\n",
|
||||
" m_mask = m << i\n",
|
||||
" return n_cleared | m_mask"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_insert_m_into_n.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_insert_m_into_n.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBit(object):\n",
|
||||
"\n",
|
||||
" def test_insert_m_into_n(self):\n",
|
||||
" n = int('0000010000111101', base=2)\n",
|
||||
" m = int('0000000000010011', base=2)\n",
|
||||
" expected = int('0000010001001101', base=2)\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_equal(bits.insert_m_into_n(m, n, i=2, j=6), expected)\n",
|
||||
" print('Success: test_insert_m_into_n')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBit()\n",
|
||||
" test.test_insert_m_into_n()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_insert_m_into_n\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_insert_m_into_n.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
21
bit_manipulation/insert_m_into_n/test_insert_m_into_n.py
Normal file
21
bit_manipulation/insert_m_into_n/test_insert_m_into_n.py
Normal file
@ -0,0 +1,21 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestBit(object):
|
||||
|
||||
def test_insert_m_into_n(self):
|
||||
n = int('0000010000111101', base=2)
|
||||
m = int('0000000000010011', base=2)
|
||||
expected = int('0000010001001101', base=2)
|
||||
bits = Bits()
|
||||
assert_equal(bits.insert_m_into_n(m, n, i=2, j=6), expected)
|
||||
print('Success: test_insert_m_into_n')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestBit()
|
||||
test.test_insert_m_into_n()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
bit_manipulation/pairwise_swap/__init__.py
Normal file
0
bit_manipulation/pairwise_swap/__init__.py
Normal file
174
bit_manipulation/pairwise_swap/pairwise_swap_challenge.ipynb
Normal file
174
bit_manipulation/pairwise_swap/pairwise_swap_challenge.ipynb
Normal file
@ -0,0 +1,174 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Swap the odd and even bits of a positive integer with as few operations as possible.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the input is always a positive int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume we're working with 32 bits?\n",
|
||||
" * Yes\n",
|
||||
"* Is the output an int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid (not None)?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> Exception\n",
|
||||
"* 0 -> 0\n",
|
||||
"* -1 -> -1\n",
|
||||
"* General case\n",
|
||||
"<pre>\n",
|
||||
" input = 1001 1111 0110\n",
|
||||
" result = 0110 1111 1001\n",
|
||||
"<pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def pairwise_swap(self, num):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_pairwise_swap.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_pairwise_swap(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_equal(bits.pairwise_swap(0), 0)\n",
|
||||
" assert_equal(bits.pairwise_swap(1), 1)\n",
|
||||
" num = int('0000100111110110', base=2)\n",
|
||||
" expected = int('0000011011111001', base=2)\n",
|
||||
" assert_equal(bits.pairwise_swap(num), expected)\n",
|
||||
" print('Success: test_pairwise_swap')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_pairwise_swap()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
219
bit_manipulation/pairwise_swap/pairwise_swap_solution.ipynb
Normal file
219
bit_manipulation/pairwise_swap/pairwise_swap_solution.ipynb
Normal file
@ -0,0 +1,219 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Swap the odd and even bits of a positive integer with as few operations as possible.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the input is always a positive int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume we're working with 32 bits?\n",
|
||||
" * Yes\n",
|
||||
"* Is the output an int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid (not None)?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> Exception\n",
|
||||
"* 0 -> 0\n",
|
||||
"* -1 -> -1\n",
|
||||
"* General case\n",
|
||||
"<pre>\n",
|
||||
" input = 0000 1001 1111 0110\n",
|
||||
" result = 0000 0110 1111 1001\n",
|
||||
"<pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"* Isolate the odd bits with a mask:\n",
|
||||
" 0000 1001 1111 0110 num\n",
|
||||
" 1010 1010 1010 1010 mask\n",
|
||||
" --------------------------------\n",
|
||||
" 0000 1000 1010 0010 num & mask\n",
|
||||
"\n",
|
||||
"* Shift the odd bits right:\n",
|
||||
" 0000 0100 0101 0001 odd\n",
|
||||
"\n",
|
||||
"* Isolate the even bits with a mask:\n",
|
||||
" 0000 1001 1111 0110 num\n",
|
||||
" 0101 0101 0101 0101 mask\n",
|
||||
" --------------------------------\n",
|
||||
" 0000 0001 0101 0100 num & mask\n",
|
||||
"\n",
|
||||
"* Shift the even bits left:\n",
|
||||
" 0000 0010 1010 1000 even\n",
|
||||
"\n",
|
||||
"* Return even | odd\n",
|
||||
" 0000 0100 0101 0001 odd\n",
|
||||
" 0000 0010 1010 1000 even\n",
|
||||
" --------------------------------\n",
|
||||
" 0000 0110 1111 1001 odd | even\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(b), where b is the number of bits\n",
|
||||
"* Space: O(b), where b is the number of bits"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def pairwise_swap(self, num):\n",
|
||||
" if num is None:\n",
|
||||
" raise TypeError('num cannot be None')\n",
|
||||
" if num == 0 or num == 1:\n",
|
||||
" return num\n",
|
||||
" odd = (num & int('1010101010101010', base=2)) >> 1\n",
|
||||
" even = (num & int('0101010101010101', base=2)) << 1\n",
|
||||
" return odd | even"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_pairwise_swap.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_pairwise_swap.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_pairwise_swap(self):\n",
|
||||
" bits = Bits()\n",
|
||||
" assert_equal(bits.pairwise_swap(0), 0)\n",
|
||||
" assert_equal(bits.pairwise_swap(1), 1)\n",
|
||||
" num = int('0000100111110110', base=2)\n",
|
||||
" expected = int('0000011011111001', base=2)\n",
|
||||
" assert_equal(bits.pairwise_swap(num), expected)\n",
|
||||
" assert_raises(TypeError, bits.pairwise_swap, None)\n",
|
||||
" \n",
|
||||
" print('Success: test_pairwise_swap')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_pairwise_swap()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_pairwise_swap\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_pairwise_swap.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
24
bit_manipulation/pairwise_swap/test_pairwise_swap.py
Normal file
24
bit_manipulation/pairwise_swap/test_pairwise_swap.py
Normal file
@ -0,0 +1,24 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestBits(object):
|
||||
|
||||
def test_pairwise_swap(self):
|
||||
bits = Bits()
|
||||
assert_equal(bits.pairwise_swap(0), 0)
|
||||
assert_equal(bits.pairwise_swap(1), 1)
|
||||
num = int('0000100111110110', base=2)
|
||||
expected = int('0000011011111001', base=2)
|
||||
assert_equal(bits.pairwise_swap(num), expected)
|
||||
assert_raises(TypeError, bits.pairwise_swap, None)
|
||||
|
||||
print('Success: test_pairwise_swap')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestBits()
|
||||
test.test_pairwise_swap()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
bit_manipulation/print_binary/__init__.py
Normal file
0
bit_manipulation/print_binary/__init__.py
Normal file
178
bit_manipulation/print_binary/print_binary_challenge.ipynb
Normal file
178
bit_manipulation/print_binary/print_binary_challenge.ipynb
Normal file
@ -0,0 +1,178 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given a real number between 0 and 1, print the binary representation. If the length of the representation is > 32, return 'ERROR'.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the input a float?\n",
|
||||
" * Yes\n",
|
||||
"* Is the output a string?\n",
|
||||
" * Yes\n",
|
||||
"* Is 0 and 1 inclusive?\n",
|
||||
" * No\n",
|
||||
"* Does the result include a trailing zero and decimal point?\n",
|
||||
" * Yes\n",
|
||||
"* Is the leading zero and decimal point counted in the 32 char limit?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> 'ERROR'\n",
|
||||
"* Out of bounds (0, 1) -> 'ERROR'\n",
|
||||
"* General case\n",
|
||||
" * 0.625 -> 0.101\n",
|
||||
" * 0.987654321 -> 'ERROR'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" def print_binary(self, num):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_print_binary.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_print_binary(self):\n",
|
||||
" bit = Bits()\n",
|
||||
" assert_equal(bit.print_binary(None), 'ERROR')\n",
|
||||
" assert_equal(bit.print_binary(0), 'ERROR')\n",
|
||||
" assert_equal(bit.print_binary(1), 'ERROR')\n",
|
||||
" num = 0.625\n",
|
||||
" expected = '0.101'\n",
|
||||
" assert_equal(bit.print_binary(num), expected)\n",
|
||||
" num = 0.987654321\n",
|
||||
" assert_equal(bit.print_binary(num), 'ERROR')\n",
|
||||
" print('Success: test_print_binary')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_print_binary()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
215
bit_manipulation/print_binary/print_binary_solution.ipynb
Normal file
215
bit_manipulation/print_binary/print_binary_solution.ipynb
Normal file
@ -0,0 +1,215 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given a real number between 0 and 1, print the binary representation. If the length of the representation is > 32, return 'ERROR'.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the input a float?\n",
|
||||
" * Yes\n",
|
||||
"* Is the output a string?\n",
|
||||
" * Yes\n",
|
||||
"* Is 0 and 1 inclusive?\n",
|
||||
" * No\n",
|
||||
"* Does the result include a trailing zero and decimal point?\n",
|
||||
" * Yes\n",
|
||||
"* Is the leading zero and decimal point counted in the 32 char limit?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> 'ERROR'\n",
|
||||
"* Out of bounds (0, 1) -> 'ERROR'\n",
|
||||
"* General case\n",
|
||||
" * 0.625 -> 0.101\n",
|
||||
" * 0.987654321 -> 'ERROR'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"* Set the result to '0.'\n",
|
||||
"* Start with a fraction of 0.5, which is 0.1 in base 2\n",
|
||||
"* Loop while num > 0\n",
|
||||
" * Check num versus fraction\n",
|
||||
" * If num > fraction, add a 1 to the result, num -= fraction\n",
|
||||
" * Else, add a 0 to the result\n",
|
||||
" * If the len(result) > 32, return 'ERROR'\n",
|
||||
" \n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(1)\n",
|
||||
"* Space: O(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from __future__ import division\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Bits(object):\n",
|
||||
"\n",
|
||||
" MAX_BITS = 32\n",
|
||||
"\n",
|
||||
" def print_binary(self, num):\n",
|
||||
" if num is None or num >= 1 or num <= 0:\n",
|
||||
" return 'ERROR'\n",
|
||||
" result = ['0', '.']\n",
|
||||
" fraction = 0.5\n",
|
||||
" while num:\n",
|
||||
" if num >= fraction:\n",
|
||||
" result.append('1')\n",
|
||||
" num -= fraction\n",
|
||||
" else:\n",
|
||||
" result.append('0')\n",
|
||||
" if len(result) > self.MAX_BITS:\n",
|
||||
" return 'ERROR'\n",
|
||||
" fraction /= 2\n",
|
||||
" return ''.join(result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_print_binary.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_print_binary.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBits(object):\n",
|
||||
"\n",
|
||||
" def test_print_binary(self):\n",
|
||||
" bit = Bits()\n",
|
||||
" assert_equal(bit.print_binary(None), 'ERROR')\n",
|
||||
" assert_equal(bit.print_binary(0), 'ERROR')\n",
|
||||
" assert_equal(bit.print_binary(1), 'ERROR')\n",
|
||||
" num = 0.625\n",
|
||||
" expected = '0.101'\n",
|
||||
" assert_equal(bit.print_binary(num), expected)\n",
|
||||
" num = 0.987654321\n",
|
||||
" assert_equal(bit.print_binary(num), 'ERROR')\n",
|
||||
" print('Success: test_print_binary')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBits()\n",
|
||||
" test.test_print_binary()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_print_binary\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_print_binary.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
25
bit_manipulation/print_binary/test_print_binary.py
Normal file
25
bit_manipulation/print_binary/test_print_binary.py
Normal file
@ -0,0 +1,25 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestBits(object):
|
||||
|
||||
def test_print_binary(self):
|
||||
bit = Bits()
|
||||
assert_equal(bit.print_binary(None), 'ERROR')
|
||||
assert_equal(bit.print_binary(0), 'ERROR')
|
||||
assert_equal(bit.print_binary(1), 'ERROR')
|
||||
num = 0.625
|
||||
expected = '0.101'
|
||||
assert_equal(bit.print_binary(num), expected)
|
||||
num = 0.987654321
|
||||
assert_equal(bit.print_binary(num), 'ERROR')
|
||||
print('Success: test_print_binary')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestBits()
|
||||
test.test_print_binary()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
graphs_trees/bst_second_largest/__init__.py
Normal file
0
graphs_trees/bst_second_largest/__init__.py
Normal file
@ -0,0 +1,212 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the second largest node in a binary search tree.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* If this is called on a None input or a single node, should we raise an exception?\n",
|
||||
" * Yes\n",
|
||||
" * None -> TypeError\n",
|
||||
" * Single node -> ValueError\n",
|
||||
"* Can we assume we already have a Node class with an insert method?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None or single node -> Exception\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"Input:\n",
|
||||
" _10_\n",
|
||||
" _/ \\_ \n",
|
||||
" 5 15\n",
|
||||
" / \\ / \\\n",
|
||||
" 3 8 12 20\n",
|
||||
" / \\ \\\n",
|
||||
" 2 4 30\n",
|
||||
"\n",
|
||||
"Output: 20\n",
|
||||
"\n",
|
||||
"Input:\n",
|
||||
" 10\n",
|
||||
" / \n",
|
||||
" 5\n",
|
||||
" / \\\n",
|
||||
" 3 7\n",
|
||||
"Output: 7\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/check_balance/check_balance_solution.ipynb). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../bst/bst.py\n",
|
||||
"%load ../bst/bst.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(Bst):\n",
|
||||
"\n",
|
||||
" def find_second_largest(self):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_bst_second_largest.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBstSecondLargest(object):\n",
|
||||
"\n",
|
||||
" def test_bst_second_largest(self):\n",
|
||||
" bst = Solution(None)\n",
|
||||
" assert_raises(TypeError, bst.find_second_largest)\n",
|
||||
" root = Node(10)\n",
|
||||
" bst = Solution(root)\n",
|
||||
" node5 = bst.insert(5)\n",
|
||||
" node15 = bst.insert(15)\n",
|
||||
" node3 = bst.insert(3)\n",
|
||||
" node8 = bst.insert(8)\n",
|
||||
" node12 = bst.insert(12)\n",
|
||||
" node20 = bst.insert(20)\n",
|
||||
" node2 = bst.insert(2)\n",
|
||||
" node4 = bst.insert(4)\n",
|
||||
" node30 = bst.insert(30)\n",
|
||||
" assert_equal(bst.find_second_largest(), node20)\n",
|
||||
" root = Node(10)\n",
|
||||
" bst = Solution(root)\n",
|
||||
" node5 = bst.insert(5)\n",
|
||||
" node3 = bst.insert(3)\n",
|
||||
" node7 = bst.insert(7)\n",
|
||||
" assert_equal(bst.find_second_largest(), node7)\n",
|
||||
" print('Success: test_bst_second_largest')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBstSecondLargest()\n",
|
||||
" test.test_bst_second_largest()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/check_balance/check_balance_solution.ipynb) for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
@ -0,0 +1,271 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the second largest node in a binary search tree.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* If this is called on a None input or a single node, should we raise an exception?\n",
|
||||
" * Yes\n",
|
||||
" * None -> TypeError\n",
|
||||
" * Single node -> ValueError\n",
|
||||
"* Can we assume we already have a Node class with an insert method?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None or single node -> Exception\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"Input:\n",
|
||||
" _10_\n",
|
||||
" _/ \\_ \n",
|
||||
" 5 15\n",
|
||||
" / \\ / \\\n",
|
||||
" 3 8 12 20\n",
|
||||
" / \\ \\\n",
|
||||
" 2 4 30\n",
|
||||
"\n",
|
||||
"Output: 20\n",
|
||||
"\n",
|
||||
"Input:\n",
|
||||
" 10\n",
|
||||
" / \n",
|
||||
" 5\n",
|
||||
" / \\\n",
|
||||
" 3 7\n",
|
||||
"Output: 7\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"\n",
|
||||
"If there is no right node, the second largest is the right most left subtree:\n",
|
||||
"\n",
|
||||
" 10\n",
|
||||
" / \n",
|
||||
" 5\n",
|
||||
" / \\\n",
|
||||
" 3 7\n",
|
||||
"\n",
|
||||
"If there is a right node and the right node has children, recurse to that right child:\n",
|
||||
"\n",
|
||||
" _10_\n",
|
||||
" _/ \\_ \n",
|
||||
" 5 15\n",
|
||||
" / \\ / \\\n",
|
||||
" 3 8 12 20\n",
|
||||
" / \\ \\\n",
|
||||
" 2 4 30\n",
|
||||
"\n",
|
||||
"Eventually we'll get to the following scenario:\n",
|
||||
"\n",
|
||||
" 20\n",
|
||||
" \\\n",
|
||||
" 30\n",
|
||||
"\n",
|
||||
"If the right node has no children, the second largest is the current node.\n",
|
||||
"\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(h)\n",
|
||||
"* Space: O(h), where h is the height of the tree"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../bst/bst.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(Bst):\n",
|
||||
"\n",
|
||||
" def _find_second_largest(self, node):\n",
|
||||
" if node.right is not None:\n",
|
||||
" if node.right.left is not None or node.right.right is not None:\n",
|
||||
" return self._find_second_largest(node.right)\n",
|
||||
" else:\n",
|
||||
" return node\n",
|
||||
" else:\n",
|
||||
" return self._find_right_most_node(node.left)\n",
|
||||
"\n",
|
||||
" def _find_right_most_node(self, node):\n",
|
||||
" if node.right is not None:\n",
|
||||
" return self._find_right_most_node(node.right)\n",
|
||||
" else:\n",
|
||||
" return node\n",
|
||||
"\n",
|
||||
" def find_second_largest(self):\n",
|
||||
" if self.root is None:\n",
|
||||
" raise TypeError('root cannot be None')\n",
|
||||
" if self.root.right is None and self.root.left is None:\n",
|
||||
" raise ValueError('root must have at least one child')\n",
|
||||
" return self._find_second_largest(self.root)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_bst_second_largest.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_bst_second_largest.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBstSecondLargest(object):\n",
|
||||
"\n",
|
||||
" def test_bst_second_largest(self):\n",
|
||||
" bst = Solution(None)\n",
|
||||
" assert_raises(TypeError, bst.find_second_largest)\n",
|
||||
" root = Node(10)\n",
|
||||
" bst = Solution(root)\n",
|
||||
" node5 = bst.insert(5)\n",
|
||||
" node15 = bst.insert(15)\n",
|
||||
" node3 = bst.insert(3)\n",
|
||||
" node8 = bst.insert(8)\n",
|
||||
" node12 = bst.insert(12)\n",
|
||||
" node20 = bst.insert(20)\n",
|
||||
" node2 = bst.insert(2)\n",
|
||||
" node4 = bst.insert(4)\n",
|
||||
" node30 = bst.insert(30)\n",
|
||||
" assert_equal(bst.find_second_largest(), node20)\n",
|
||||
" root = Node(10)\n",
|
||||
" bst = Solution(root)\n",
|
||||
" node5 = bst.insert(5)\n",
|
||||
" node3 = bst.insert(3)\n",
|
||||
" node7 = bst.insert(7)\n",
|
||||
" assert_equal(bst.find_second_largest(), node7)\n",
|
||||
" print('Success: test_bst_second_largest')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBstSecondLargest()\n",
|
||||
" test.test_bst_second_largest()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_bst_second_largest\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_bst_second_largest.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
36
graphs_trees/bst_second_largest/test_bst_second_largest.py
Normal file
36
graphs_trees/bst_second_largest/test_bst_second_largest.py
Normal file
@ -0,0 +1,36 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestBstSecondLargest(object):
|
||||
|
||||
def test_bst_second_largest(self):
|
||||
bst = Solution(None)
|
||||
assert_raises(TypeError, bst.find_second_largest)
|
||||
root = Node(10)
|
||||
bst = Solution(root)
|
||||
node5 = bst.insert(5)
|
||||
node15 = bst.insert(15)
|
||||
node3 = bst.insert(3)
|
||||
node8 = bst.insert(8)
|
||||
node12 = bst.insert(12)
|
||||
node20 = bst.insert(20)
|
||||
node2 = bst.insert(2)
|
||||
node4 = bst.insert(4)
|
||||
node30 = bst.insert(30)
|
||||
assert_equal(bst.find_second_largest(), node20)
|
||||
root = Node(10)
|
||||
bst = Solution(root)
|
||||
node5 = bst.insert(5)
|
||||
node3 = bst.insert(3)
|
||||
node7 = bst.insert(7)
|
||||
assert_equal(bst.find_second_largest(), node7)
|
||||
print('Success: test_bst_second_largest')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestBstSecondLargest()
|
||||
test.test_bst_second_largest()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -104,16 +104,16 @@
|
||||
"source": [
|
||||
"class BstBalance(Bst):\n",
|
||||
"\n",
|
||||
" def _check_height(self, node):\n",
|
||||
" def _check_balance(self, node):\n",
|
||||
" if node is None:\n",
|
||||
" return 0\n",
|
||||
" left_height = self._check_height(node.left)\n",
|
||||
" left_height = self._check_balance(node.left)\n",
|
||||
" if left_height == -1:\n",
|
||||
" return -1\n",
|
||||
" right_height = self._check_height(node.right)\n",
|
||||
" right_height = self._check_balance(node.right)\n",
|
||||
" if right_height == -1:\n",
|
||||
" return -1\n",
|
||||
" diff = abs(left_height-right_height)\n",
|
||||
" diff = abs(left_height - right_height)\n",
|
||||
" if diff > 1:\n",
|
||||
" return -1\n",
|
||||
" return 1 + max(left_height, right_height)\n",
|
||||
@ -121,7 +121,7 @@
|
||||
" def check_balance(self):\n",
|
||||
" if self.root is None:\n",
|
||||
" raise TypeError('root cannot be None')\n",
|
||||
" height = self._check_height(self.root)\n",
|
||||
" height = self._check_balance(self.root)\n",
|
||||
" return height != -1"
|
||||
]
|
||||
},
|
||||
@ -235,7 +235,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
0
graphs_trees/graph_build_order/__init__.py
Normal file
0
graphs_trees/graph_build_order/__init__.py
Normal file
242
graphs_trees/graph_build_order/build_order_challenge.ipynb
Normal file
242
graphs_trees/graph_build_order/build_order_challenge.ipynb
Normal file
@ -0,0 +1,242 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find a build order given a list of projects and dependencies.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is it possible to have a cyclic graph as the input?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume we already have Graph and Node classes?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this is a connected graph?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* projects: a, b, c, d, e, f, g\n",
|
||||
"* dependencies: (d, g), (f, c), (f, b), (f, a), (c, a), (b, a), (a, e), (b, e)\n",
|
||||
"* output: d, f, c, b, g, a, e\n",
|
||||
"\n",
|
||||
"Note: Edge direction is down\n",
|
||||
"<pre>\n",
|
||||
" f d\n",
|
||||
" /|\\ |\n",
|
||||
" c | b g\n",
|
||||
" \\|/|\n",
|
||||
" a |\n",
|
||||
" |/\n",
|
||||
" e\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Test a graph with a cycle, output should be None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](https://github.com/donnemartin/interactive-coding-challenges/graphs_trees/build_order/build_order_solution.ipynb). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Dependency(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, node_key_before, node_key_after):\n",
|
||||
" self.node_key_before = node_key_before\n",
|
||||
" self.node_key_after = node_key_after"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../graph/graph.py\n",
|
||||
"%load ../graph/graph.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class BuildOrder(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, dependencies):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def find_build_order(self):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_build_order.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"from nose.tools import assert_true\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBuildOrder(object):\n",
|
||||
"\n",
|
||||
" def __init__(self):\n",
|
||||
" self.dependencies = [\n",
|
||||
" Dependency('d', 'g'),\n",
|
||||
" Dependency('f', 'c'),\n",
|
||||
" Dependency('f', 'b'),\n",
|
||||
" Dependency('f', 'a'),\n",
|
||||
" Dependency('c', 'a'),\n",
|
||||
" Dependency('b', 'a'),\n",
|
||||
" Dependency('a', 'e'),\n",
|
||||
" Dependency('b', 'e'),\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" def test_build_order(self):\n",
|
||||
" build_order = BuildOrder(self.dependencies)\n",
|
||||
" processed_nodes = build_order.find_build_order()\n",
|
||||
"\n",
|
||||
" expected_result0 = ('d', 'f')\n",
|
||||
" expected_result1 = ('c', 'b', 'g')\n",
|
||||
" assert_true(processed_nodes[0].key in expected_result0)\n",
|
||||
" assert_true(processed_nodes[1].key in expected_result0)\n",
|
||||
" assert_true(processed_nodes[2].key in expected_result1)\n",
|
||||
" assert_true(processed_nodes[3].key in expected_result1)\n",
|
||||
" assert_true(processed_nodes[4].key in expected_result1)\n",
|
||||
" assert_true(processed_nodes[5].key is 'a')\n",
|
||||
" assert_true(processed_nodes[6].key is 'e')\n",
|
||||
"\n",
|
||||
" print('Success: test_build_order')\n",
|
||||
"\n",
|
||||
" def test_build_order_circular(self):\n",
|
||||
" self.dependencies.append(Dependency('e', 'f'))\n",
|
||||
" build_order = BuildOrder(self.dependencies)\n",
|
||||
" processed_nodes = build_order.find_build_order()\n",
|
||||
" assert_true(processed_nodes is None)\n",
|
||||
"\n",
|
||||
" print('Success: test_build_order_circular')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBuildOrder()\n",
|
||||
" test.test_build_order()\n",
|
||||
" test.test_build_order_circular()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook](https://github.com/donnemartin/interactive-coding-challenges/graphs_trees/build_order/build_order_solution.ipynb) for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
310
graphs_trees/graph_build_order/build_order_solution.ipynb
Normal file
310
graphs_trees/graph_build_order/build_order_solution.ipynb
Normal file
@ -0,0 +1,310 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find a build order given a list of projects and dependencies.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is it possible to have a cyclic graph as the input?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume we already have Graph and Node classes?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this is a connected graph?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* projects: a, b, c, d, e, f, g\n",
|
||||
"* dependencies: (d, g), (f, c), (f, b), (f, a), (c, a), (b, a), (a, e), (b, e)\n",
|
||||
"* output: d, f, c, b, g, a, e\n",
|
||||
"\n",
|
||||
"Note: Edge direction is down\n",
|
||||
"<pre>\n",
|
||||
" f d\n",
|
||||
" /|\\ |\n",
|
||||
" c | b g\n",
|
||||
" \\|/|\n",
|
||||
" a |\n",
|
||||
" |/\n",
|
||||
" e\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Test a graph with a cycle, output should be None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"We can determine the build order using a topological sort.\n",
|
||||
"\n",
|
||||
"* Build the graph with projects (nodes) and dependencies (directed edges)\n",
|
||||
"* Add initially non-dependent nodes to processed_nodes\n",
|
||||
" * If none exist, we have a circular dependency, return None\n",
|
||||
"* While the length processed_nodes < the length of graph nodes\n",
|
||||
" * Remove outgoing edges from newly added items in processed_nodes\n",
|
||||
" * Add non-dependent nodes to processed_nodes\n",
|
||||
" * If we didn't add any nodes, we have a circular dependency, return None\n",
|
||||
"* Return processed_nodes\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(V + E)\n",
|
||||
"* Space: O(V + E)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from collections import deque\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Dependency(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, node_key_before, node_key_after):\n",
|
||||
" self.node_key_before = node_key_before\n",
|
||||
" self.node_key_after = node_key_after"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../graph/graph.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class BuildOrder(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, dependencies):\n",
|
||||
" self.dependencies = dependencies\n",
|
||||
" self.graph = Graph()\n",
|
||||
" self._build_graph()\n",
|
||||
"\n",
|
||||
" def _build_graph(self):\n",
|
||||
" for dependency in self.dependencies:\n",
|
||||
" self.graph.add_edge(dependency.node_key_before,\n",
|
||||
" dependency.node_key_after)\n",
|
||||
"\n",
|
||||
" def _find_start_nodes(self, processed_nodes):\n",
|
||||
" nodes_to_process = {}\n",
|
||||
" for key, node in self.graph.nodes.items():\n",
|
||||
" if node.incoming_edges == 0 and key not in processed_nodes:\n",
|
||||
" nodes_to_process[key] = node\n",
|
||||
" return nodes_to_process\n",
|
||||
"\n",
|
||||
" def _process_nodes(self, nodes_to_process, processed_nodes):\n",
|
||||
" for node in nodes_to_process.values():\n",
|
||||
" # We'll need to iterate on copies since we'll need\n",
|
||||
" # to change the dictionaries during iteration with\n",
|
||||
" # the remove_neighbor call\n",
|
||||
" for adj_node in list(node.adj_nodes.values()):\n",
|
||||
" node.remove_neighbor(adj_node)\n",
|
||||
" processed_nodes[node.key] = node\n",
|
||||
" nodes_to_process = {}\n",
|
||||
"\n",
|
||||
" def find_build_order(self):\n",
|
||||
" result = []\n",
|
||||
" nodes_to_process = {}\n",
|
||||
" processed_nodes = {}\n",
|
||||
" while len(result) != len(self.graph.nodes):\n",
|
||||
" nodes_to_process = self._find_start_nodes(processed_nodes)\n",
|
||||
" if not nodes_to_process:\n",
|
||||
" return None\n",
|
||||
" result.extend(nodes_to_process.values())\n",
|
||||
" self._process_nodes(nodes_to_process, processed_nodes)\n",
|
||||
" return result"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../utils/results.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_build_order.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_build_order.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"from nose.tools import assert_true\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestBuildOrder(object):\n",
|
||||
"\n",
|
||||
" def __init__(self):\n",
|
||||
" self.dependencies = [\n",
|
||||
" Dependency('d', 'g'),\n",
|
||||
" Dependency('f', 'c'),\n",
|
||||
" Dependency('f', 'b'),\n",
|
||||
" Dependency('f', 'a'),\n",
|
||||
" Dependency('c', 'a'),\n",
|
||||
" Dependency('b', 'a'),\n",
|
||||
" Dependency('a', 'e'),\n",
|
||||
" Dependency('b', 'e'),\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" def test_build_order(self):\n",
|
||||
" build_order = BuildOrder(self.dependencies)\n",
|
||||
" processed_nodes = build_order.find_build_order()\n",
|
||||
"\n",
|
||||
" expected_result0 = ('d', 'f')\n",
|
||||
" expected_result1 = ('c', 'b', 'g')\n",
|
||||
" assert_true(processed_nodes[0].key in expected_result0)\n",
|
||||
" assert_true(processed_nodes[1].key in expected_result0)\n",
|
||||
" assert_true(processed_nodes[2].key in expected_result1)\n",
|
||||
" assert_true(processed_nodes[3].key in expected_result1)\n",
|
||||
" assert_true(processed_nodes[4].key in expected_result1)\n",
|
||||
" assert_true(processed_nodes[5].key is 'a')\n",
|
||||
" assert_true(processed_nodes[6].key is 'e')\n",
|
||||
"\n",
|
||||
" print('Success: test_build_order')\n",
|
||||
"\n",
|
||||
" def test_build_order_circular(self):\n",
|
||||
" self.dependencies.append(Dependency('e', 'f'))\n",
|
||||
" build_order = BuildOrder(self.dependencies)\n",
|
||||
" processed_nodes = build_order.find_build_order()\n",
|
||||
" assert_true(processed_nodes is None)\n",
|
||||
"\n",
|
||||
" print('Success: test_build_order_circular')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestBuildOrder()\n",
|
||||
" test.test_build_order()\n",
|
||||
" test.test_build_order_circular()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_build_order\n",
|
||||
"Success: test_build_order_circular\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_build_order.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
51
graphs_trees/graph_build_order/test_build_order.py
Normal file
51
graphs_trees/graph_build_order/test_build_order.py
Normal file
@ -0,0 +1,51 @@
|
||||
from nose.tools import assert_equal
|
||||
from nose.tools import assert_true
|
||||
|
||||
|
||||
class TestBuildOrder(object):
|
||||
|
||||
def __init__(self):
|
||||
self.dependencies = [
|
||||
Dependency('d', 'g'),
|
||||
Dependency('f', 'c'),
|
||||
Dependency('f', 'b'),
|
||||
Dependency('f', 'a'),
|
||||
Dependency('c', 'a'),
|
||||
Dependency('b', 'a'),
|
||||
Dependency('a', 'e'),
|
||||
Dependency('b', 'e'),
|
||||
]
|
||||
|
||||
def test_build_order(self):
|
||||
build_order = BuildOrder(self.dependencies)
|
||||
processed_nodes = build_order.find_build_order()
|
||||
|
||||
expected_result0 = ('d', 'f')
|
||||
expected_result1 = ('c', 'b', 'g')
|
||||
assert_true(processed_nodes[0].key in expected_result0)
|
||||
assert_true(processed_nodes[1].key in expected_result0)
|
||||
assert_true(processed_nodes[2].key in expected_result1)
|
||||
assert_true(processed_nodes[3].key in expected_result1)
|
||||
assert_true(processed_nodes[4].key in expected_result1)
|
||||
assert_true(processed_nodes[5].key is 'a')
|
||||
assert_true(processed_nodes[6].key is 'e')
|
||||
|
||||
print('Success: test_build_order')
|
||||
|
||||
def test_build_order_circular(self):
|
||||
self.dependencies.append(Dependency('e', 'f'))
|
||||
build_order = BuildOrder(self.dependencies)
|
||||
processed_nodes = build_order.find_build_order()
|
||||
assert_true(processed_nodes is None)
|
||||
|
||||
print('Success: test_build_order_circular')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestBuildOrder()
|
||||
test.test_build_order()
|
||||
test.test_build_order_circular()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
graphs_trees/graph_shortest_path/__init__.py
Normal file
0
graphs_trees/graph_shortest_path/__init__.py
Normal file
@ -0,0 +1,255 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the shortest path between two nodes in a graph.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is this a directional graph?\n",
|
||||
" * Yes\n",
|
||||
"* Could the graph have cycles?\n",
|
||||
" * Yes\n",
|
||||
" * Note: If the answer were no, this would be a DAG. \n",
|
||||
" * DAGs can be solved with a [topological sort](http://www.geeksforgeeks.org/shortest-path-for-directed-acyclic-graphs/)\n",
|
||||
"* Are the edges weighted?\n",
|
||||
" * Yes\n",
|
||||
" * Note: If the edges were not weighted, we could do a BFS\n",
|
||||
"* Are the edges all non-negative numbers?\n",
|
||||
" * Yes\n",
|
||||
" * Note: Graphs with negative edges can be done with Bellman-Ford\n",
|
||||
" * Graphs with negative cost cycles do not have a defined shortest path\n",
|
||||
"* Do we have to check for non-negative edges?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this is a connected graph?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume we already have a graph class?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume we already have a priority queue class?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"The constaints state we don't have to check for negative edges, so we test with the general case.\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"graph.add_edge('a', 'b', weight=5)\n",
|
||||
"graph.add_edge('a', 'c', weight=3)\n",
|
||||
"graph.add_edge('a', 'e', weight=2)\n",
|
||||
"graph.add_edge('b', 'd', weight=2)\n",
|
||||
"graph.add_edge('c', 'b', weight=1)\n",
|
||||
"graph.add_edge('c', 'd', weight=1)\n",
|
||||
"graph.add_edge('d', 'a', weight=1)\n",
|
||||
"graph.add_edge('d', 'g', weight=2)\n",
|
||||
"graph.add_edge('d', 'h', weight=1)\n",
|
||||
"graph.add_edge('e', 'a', weight=1)\n",
|
||||
"graph.add_edge('e', 'h', weight=4)\n",
|
||||
"graph.add_edge('e', 'i', weight=7)\n",
|
||||
"graph.add_edge('f', 'b', weight=3)\n",
|
||||
"graph.add_edge('f', 'g', weight=1)\n",
|
||||
"graph.add_edge('g', 'c', weight=3)\n",
|
||||
"graph.add_edge('g', 'i', weight=2)\n",
|
||||
"graph.add_edge('h', 'c', weight=2)\n",
|
||||
"graph.add_edge('h', 'f', weight=2)\n",
|
||||
"graph.add_edge('h', 'g', weight=2)\n",
|
||||
"shortest_path = ShortestPath(graph)\n",
|
||||
"result = shortest_path.find_shortest_path('a', 'i')\n",
|
||||
"assert_equal(result, ['a', 'c', 'd', 'g', 'i'])\n",
|
||||
"assert_equal(shortest_path.path_weight['i'], 8)\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](https://github.com/donnemartin/interactive-coding-challenges/graphs_trees/graph_shortest_path/graph_shortest_path_solution.ipynb). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../../arrays_strings/priority_queue/priority_queue.py\n",
|
||||
"%load ../../arrays_strings/priority_queue/priority_queue.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../graph/graph.py\n",
|
||||
"%load ../graph/graph.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class ShortestPath(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, graph):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def find_shortest_path(self, start_node_key, end_node_key):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_shortest_path.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestShortestPath(object):\n",
|
||||
"\n",
|
||||
" def test_shortest_path(self):\n",
|
||||
" graph = Graph()\n",
|
||||
" graph.add_edge('a', 'b', weight=5)\n",
|
||||
" graph.add_edge('a', 'c', weight=3)\n",
|
||||
" graph.add_edge('a', 'e', weight=2)\n",
|
||||
" graph.add_edge('b', 'd', weight=2)\n",
|
||||
" graph.add_edge('c', 'b', weight=1)\n",
|
||||
" graph.add_edge('c', 'd', weight=1)\n",
|
||||
" graph.add_edge('d', 'a', weight=1)\n",
|
||||
" graph.add_edge('d', 'g', weight=2)\n",
|
||||
" graph.add_edge('d', 'h', weight=1)\n",
|
||||
" graph.add_edge('e', 'a', weight=1)\n",
|
||||
" graph.add_edge('e', 'h', weight=4)\n",
|
||||
" graph.add_edge('e', 'i', weight=7)\n",
|
||||
" graph.add_edge('f', 'b', weight=3)\n",
|
||||
" graph.add_edge('f', 'g', weight=1)\n",
|
||||
" graph.add_edge('g', 'c', weight=3)\n",
|
||||
" graph.add_edge('g', 'i', weight=2)\n",
|
||||
" graph.add_edge('h', 'c', weight=2)\n",
|
||||
" graph.add_edge('h', 'f', weight=2)\n",
|
||||
" graph.add_edge('h', 'g', weight=2)\n",
|
||||
" shortest_path = ShortestPath(graph)\n",
|
||||
" result = shortest_path.find_shortest_path('a', 'i')\n",
|
||||
" assert_equal(result, ['a', 'c', 'd', 'g', 'i'])\n",
|
||||
" assert_equal(shortest_path.path_weight['i'], 8)\n",
|
||||
"\n",
|
||||
" print('Success: test_shortest_path')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestShortestPath()\n",
|
||||
" test.test_shortest_path()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook](https://github.com/donnemartin/interactive-coding-challenges/graphs_trees/graph_shortest_path/graph_shortest_path_solution.ipynb) for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
@ -0,0 +1,355 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the shortest path between two nodes in a graph.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is this a directional graph?\n",
|
||||
" * Yes\n",
|
||||
"* Could the graph have cycles?\n",
|
||||
" * Yes\n",
|
||||
" * Note: If the answer were no, this would be a DAG. \n",
|
||||
" * DAGs can be solved with a [topological sort](http://www.geeksforgeeks.org/shortest-path-for-directed-acyclic-graphs/)\n",
|
||||
"* Are the edges weighted?\n",
|
||||
" * Yes\n",
|
||||
" * Note: If the edges were not weighted, we could do a BFS\n",
|
||||
"* Are the edges all non-negative numbers?\n",
|
||||
" * Yes\n",
|
||||
" * Note: Graphs with negative edges can be done with Bellman-Ford\n",
|
||||
" * Graphs with negative cost cycles do not have a defined shortest path\n",
|
||||
"* Do we have to check for non-negative edges?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this is a connected graph?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume we already have a graph class?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume we already have a priority queue class?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"The constaints state we don't have to check for negative edges, so we test with the general case.\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"graph.add_edge('a', 'b', weight=5)\n",
|
||||
"graph.add_edge('a', 'c', weight=3)\n",
|
||||
"graph.add_edge('a', 'e', weight=2)\n",
|
||||
"graph.add_edge('b', 'd', weight=2)\n",
|
||||
"graph.add_edge('c', 'b', weight=1)\n",
|
||||
"graph.add_edge('c', 'd', weight=1)\n",
|
||||
"graph.add_edge('d', 'a', weight=1)\n",
|
||||
"graph.add_edge('d', 'g', weight=2)\n",
|
||||
"graph.add_edge('d', 'h', weight=1)\n",
|
||||
"graph.add_edge('e', 'a', weight=1)\n",
|
||||
"graph.add_edge('e', 'h', weight=4)\n",
|
||||
"graph.add_edge('e', 'i', weight=7)\n",
|
||||
"graph.add_edge('f', 'b', weight=3)\n",
|
||||
"graph.add_edge('f', 'g', weight=1)\n",
|
||||
"graph.add_edge('g', 'c', weight=3)\n",
|
||||
"graph.add_edge('g', 'i', weight=2)\n",
|
||||
"graph.add_edge('h', 'c', weight=2)\n",
|
||||
"graph.add_edge('h', 'f', weight=2)\n",
|
||||
"graph.add_edge('h', 'g', weight=2)\n",
|
||||
"shortest_path = ShortestPath(graph)\n",
|
||||
"result = shortest_path.find_shortest_path('a', 'i')\n",
|
||||
"assert_equal(result, ['a', 'c', 'd', 'g', 'i'])\n",
|
||||
"assert_equal(shortest_path.path_weight['i'], 8)\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Wikipedia's animation:\n",
|
||||
"\n",
|
||||
"![](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)\n",
|
||||
"\n",
|
||||
"Initialize the following:\n",
|
||||
"\n",
|
||||
"* previous = {} # Key: node key, val: prev node key, shortest path\n",
|
||||
" * Set each node's previous node key to None\n",
|
||||
"* path_weight = {} # Key: node key, val: weight, shortest path\n",
|
||||
" * Set each node's shortest path weight to infinity\n",
|
||||
"* remaining = PriorityQueue() # Queue of node key, path weight\n",
|
||||
" * Add each node's shortest path weight to the priority queue\n",
|
||||
"\n",
|
||||
"* Set the start node's path_weight to 0 and update the value in remaining\n",
|
||||
"* Loop while remaining still has items\n",
|
||||
" * Extract the min node (node with minimum path weight) from remaining\n",
|
||||
" * Loop through each adjacent node in the min node\n",
|
||||
" * Calculate the new weight:\n",
|
||||
" * Adjacent node's edge weight + the min node's path_weight \n",
|
||||
" * If the newly calculated path is less than the adjacent node's current path_weight:\n",
|
||||
" * Set the node's previous node key leading to the shortest path\n",
|
||||
" * Update the adjacent node's shortest path and update the value in the priority queue\n",
|
||||
"* Walk backwards to determine the shortest path:\n",
|
||||
" * Start at the end node, walk the previous dict to get to the start node\n",
|
||||
"* Reverse the list and return it\n",
|
||||
"\n",
|
||||
"### Complexity for array-based priority queue:\n",
|
||||
"\n",
|
||||
"* Time: O(v^2), where v is the number of vertices\n",
|
||||
"* Space: O(v^2)\n",
|
||||
"\n",
|
||||
"This might be better than the min-heap-based variant if the graph has a lot of edges.\n",
|
||||
"\n",
|
||||
"O(v^2) is better than O((v + v^2) log v).\n",
|
||||
"\n",
|
||||
"### Complexity for min-heap-based priority queue:\n",
|
||||
"\n",
|
||||
"* Time: O((v + e) log v), where v is the number of vertices, e is the number of edges\n",
|
||||
"* Space: O((v + e) log v)\n",
|
||||
"\n",
|
||||
"This might be better than the array-based variant if the graph is sparse."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../../arrays_strings/priority_queue/priority_queue.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../graph/graph.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class ShortestPath(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, graph):\n",
|
||||
" if graph is None:\n",
|
||||
" raise TypeError('graph cannot be None')\n",
|
||||
" self.graph = graph\n",
|
||||
" self.previous = {} # Key: node key, val: prev node key, shortest path\n",
|
||||
" self.path_weight = {} # Key: node key, val: weight, shortest path\n",
|
||||
" self.remaining = PriorityQueue() # Queue of node key, path weight\n",
|
||||
" for key in self.graph.nodes.keys():\n",
|
||||
" # Set each node's previous node key to None\n",
|
||||
" # Set each node's shortest path weight to infinity\n",
|
||||
" # Add each node's shortest path weight to the priority queue\n",
|
||||
" self.previous[key] = None\n",
|
||||
" self.path_weight[key] = sys.maxsize\n",
|
||||
" self.remaining.insert(\n",
|
||||
" PriorityQueueNode(key, self.path_weight[key]))\n",
|
||||
"\n",
|
||||
" def find_shortest_path(self, start_node_key, end_node_key):\n",
|
||||
" if start_node_key is None or end_node_key is None:\n",
|
||||
" raise TypeError('Input node keys cannot be None')\n",
|
||||
" if (start_node_key not in self.graph.nodes or\n",
|
||||
" end_node_key not in self.graph.nodes):\n",
|
||||
" raise ValueError('Invalid start or end node key')\n",
|
||||
" # Set the start node's shortest path weight to 0\n",
|
||||
" # and update the value in the priority queue\n",
|
||||
" self.path_weight[start_node_key] = 0\n",
|
||||
" self.remaining.decrease_key(start_node_key, 0)\n",
|
||||
" while self.remaining:\n",
|
||||
" # Extract the min node (node with minimum path weight)\n",
|
||||
" # from the priority queue\n",
|
||||
" min_node_key = self.remaining.extract_min().obj\n",
|
||||
" min_node = self.graph.nodes[min_node_key]\n",
|
||||
" # Loop through each adjacent node in the min node\n",
|
||||
" for adj_key in min_node.adj_nodes.keys():\n",
|
||||
" # Node's path:\n",
|
||||
" # Adjacent node's edge weight + the min node's\n",
|
||||
" # shortest path weight\n",
|
||||
" new_weight = (min_node.adj_weights[adj_key] +\n",
|
||||
" self.path_weight[min_node_key])\n",
|
||||
" # Only update if the newly calculated path is\n",
|
||||
" # less than the existing node's shortest path\n",
|
||||
" if self.path_weight[adj_key] > new_weight:\n",
|
||||
" # Set the node's previous node key leading to the shortest path\n",
|
||||
" # Update the adjacent node's shortest path and\n",
|
||||
" # update the value in the priority queue\n",
|
||||
" self.previous[adj_key] = min_node_key\n",
|
||||
" self.path_weight[adj_key] = new_weight\n",
|
||||
" self.remaining.decrease_key(adj_key, new_weight)\n",
|
||||
" # Walk backwards to determine the shortest path:\n",
|
||||
" # Start at the end node, walk the previous dict to get to the start node\n",
|
||||
" result = []\n",
|
||||
" current_node_key = end_node_key\n",
|
||||
" while current_node_key is not None:\n",
|
||||
" result.append(current_node_key)\n",
|
||||
" current_node_key = self.previous[current_node_key]\n",
|
||||
" # Reverse the list\n",
|
||||
" return result[::-1]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_shortest_path.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_shortest_path.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestShortestPath(object):\n",
|
||||
"\n",
|
||||
" def test_shortest_path(self):\n",
|
||||
" graph = Graph()\n",
|
||||
" graph.add_edge('a', 'b', weight=5)\n",
|
||||
" graph.add_edge('a', 'c', weight=3)\n",
|
||||
" graph.add_edge('a', 'e', weight=2)\n",
|
||||
" graph.add_edge('b', 'd', weight=2)\n",
|
||||
" graph.add_edge('c', 'b', weight=1)\n",
|
||||
" graph.add_edge('c', 'd', weight=1)\n",
|
||||
" graph.add_edge('d', 'a', weight=1)\n",
|
||||
" graph.add_edge('d', 'g', weight=2)\n",
|
||||
" graph.add_edge('d', 'h', weight=1)\n",
|
||||
" graph.add_edge('e', 'a', weight=1)\n",
|
||||
" graph.add_edge('e', 'h', weight=4)\n",
|
||||
" graph.add_edge('e', 'i', weight=7)\n",
|
||||
" graph.add_edge('f', 'b', weight=3)\n",
|
||||
" graph.add_edge('f', 'g', weight=1)\n",
|
||||
" graph.add_edge('g', 'c', weight=3)\n",
|
||||
" graph.add_edge('g', 'i', weight=2)\n",
|
||||
" graph.add_edge('h', 'c', weight=2)\n",
|
||||
" graph.add_edge('h', 'f', weight=2)\n",
|
||||
" graph.add_edge('h', 'g', weight=2)\n",
|
||||
" shortest_path = ShortestPath(graph)\n",
|
||||
" result = shortest_path.find_shortest_path('a', 'i')\n",
|
||||
" assert_equal(result, ['a', 'c', 'd', 'g', 'i'])\n",
|
||||
" assert_equal(shortest_path.path_weight['i'], 8)\n",
|
||||
"\n",
|
||||
" print('Success: test_shortest_path')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestShortestPath()\n",
|
||||
" test.test_shortest_path()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_shortest_path\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_shortest_path.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
41
graphs_trees/graph_shortest_path/priority_queue.py
Normal file
41
graphs_trees/graph_shortest_path/priority_queue.py
Normal file
@ -0,0 +1,41 @@
|
||||
import sys
|
||||
|
||||
|
||||
class PriorityQueueNode(object):
|
||||
|
||||
def __init__(self, obj, key):
|
||||
self.obj = obj
|
||||
self.key = key
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.obj) + ': ' + str(self.key)
|
||||
|
||||
|
||||
class PriorityQueue(object):
|
||||
|
||||
def __init__(self):
|
||||
self.queue = []
|
||||
|
||||
def insert(self, node):
|
||||
if node is not None:
|
||||
self.queue.append(node)
|
||||
return self.queue[-1]
|
||||
return None
|
||||
|
||||
def extract_min(self):
|
||||
if not self.queue:
|
||||
return None
|
||||
minimum = sys.maxsize
|
||||
for index, node in enumerate(self.queue):
|
||||
if node.key < minimum:
|
||||
minimum = node.key
|
||||
minimum_index = index
|
||||
node = self.queue.pop(minimum_index)
|
||||
return node.obj
|
||||
|
||||
def decrease_key(self, obj, new_key):
|
||||
for node in self.queue:
|
||||
if node.obj is obj:
|
||||
node.key = new_key
|
||||
return node
|
||||
return None
|
41
graphs_trees/graph_shortest_path/test_shortest_path.py
Normal file
41
graphs_trees/graph_shortest_path/test_shortest_path.py
Normal file
@ -0,0 +1,41 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestShortestPath(object):
|
||||
|
||||
def test_shortest_path(self):
|
||||
graph = Graph()
|
||||
graph.add_edge('a', 'b', weight=5)
|
||||
graph.add_edge('a', 'c', weight=3)
|
||||
graph.add_edge('a', 'e', weight=2)
|
||||
graph.add_edge('b', 'd', weight=2)
|
||||
graph.add_edge('c', 'b', weight=1)
|
||||
graph.add_edge('c', 'd', weight=1)
|
||||
graph.add_edge('d', 'a', weight=1)
|
||||
graph.add_edge('d', 'g', weight=2)
|
||||
graph.add_edge('d', 'h', weight=1)
|
||||
graph.add_edge('e', 'a', weight=1)
|
||||
graph.add_edge('e', 'h', weight=4)
|
||||
graph.add_edge('e', 'i', weight=7)
|
||||
graph.add_edge('f', 'b', weight=3)
|
||||
graph.add_edge('f', 'g', weight=1)
|
||||
graph.add_edge('g', 'c', weight=3)
|
||||
graph.add_edge('g', 'i', weight=2)
|
||||
graph.add_edge('h', 'c', weight=2)
|
||||
graph.add_edge('h', 'f', weight=2)
|
||||
graph.add_edge('h', 'g', weight=2)
|
||||
shortest_path = ShortestPath(graph)
|
||||
result = shortest_path.find_shortest_path('a', 'i')
|
||||
assert_equal(result, ['a', 'c', 'd', 'g', 'i'])
|
||||
assert_equal(shortest_path.path_weight['i'], 8)
|
||||
|
||||
print('Success: test_shortest_path')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestShortestPath()
|
||||
test.test_shortest_path()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -0,0 +1,215 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the shortest path between two nodes in a graph.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the graph directed?\n",
|
||||
" * Yes\n",
|
||||
"* Is the graph weighted?\n",
|
||||
" * No\n",
|
||||
"* Can we assume we already have Graph and Node classes?\n",
|
||||
" * Yes\n",
|
||||
"* Are the inputs two Nodes?\n",
|
||||
" * Yes\n",
|
||||
"* Is the output a list of Node keys that make up the shortest path?\n",
|
||||
" * Yes\n",
|
||||
"* If there is no path, should we return None?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this is a connected graph?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"Input:\n",
|
||||
"* `add_edge(source, destination, weight)`\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"graph.add_edge(0, 1)\n",
|
||||
"graph.add_edge(0, 4)\n",
|
||||
"graph.add_edge(0, 5)\n",
|
||||
"graph.add_edge(1, 3)\n",
|
||||
"graph.add_edge(1, 4)\n",
|
||||
"graph.add_edge(2, 1)\n",
|
||||
"graph.add_edge(3, 2)\n",
|
||||
"graph.add_edge(3, 4)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Result:\n",
|
||||
"* search_path(start=0, end=2) -> [0, 1, 3, 2]\n",
|
||||
"* search_path(start=0, end=0) -> [0]\n",
|
||||
"* search_path(start=4, end=5) -> None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_path_exists/path_exists_solution.ipynb). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../graph/graph.py\n",
|
||||
"%load ../graph/graph.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class GraphShortestPath(Graph):\n",
|
||||
"\n",
|
||||
" def shortest_path(self, source_key, dest_key):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_shortest_path.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestShortestPath(object):\n",
|
||||
"\n",
|
||||
" def test_shortest_path(self):\n",
|
||||
" nodes = []\n",
|
||||
" graph = GraphShortestPath()\n",
|
||||
" for id in range(0, 6):\n",
|
||||
" nodes.append(graph.add_node(id))\n",
|
||||
" graph.add_edge(0, 1)\n",
|
||||
" graph.add_edge(0, 4)\n",
|
||||
" graph.add_edge(0, 5)\n",
|
||||
" graph.add_edge(1, 3)\n",
|
||||
" graph.add_edge(1, 4)\n",
|
||||
" graph.add_edge(2, 1)\n",
|
||||
" graph.add_edge(3, 2)\n",
|
||||
" graph.add_edge(3, 4)\n",
|
||||
"\n",
|
||||
" assert_equal(graph.shortest_path(nodes[0].key, nodes[2].key), [0, 1, 3, 2])\n",
|
||||
" assert_equal(graph.shortest_path(nodes[0].key, nodes[0].key), [0])\n",
|
||||
" assert_equal(graph.shortest_path(nodes[4].key, nodes[5].key), None)\n",
|
||||
"\n",
|
||||
" print('Success: test_shortest_path')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestShortestPath()\n",
|
||||
" test.test_shortest_path()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_path_exists/path_exists_solution.ipynb) for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
@ -0,0 +1,274 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the shortest path between two nodes in a graph.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the graph directed?\n",
|
||||
" * Yes\n",
|
||||
"* Is the graph weighted?\n",
|
||||
" * No\n",
|
||||
"* Can we assume we already have Graph and Node classes?\n",
|
||||
" * Yes\n",
|
||||
"* Are the inputs two Nodes?\n",
|
||||
" * Yes\n",
|
||||
"* Is the output a list of Node keys that make up the shortest path?\n",
|
||||
" * Yes\n",
|
||||
"* If there is no path, should we return None?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this is a connected graph?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"Input:\n",
|
||||
"* `add_edge(source, destination, weight)`\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"graph.add_edge(0, 1)\n",
|
||||
"graph.add_edge(0, 4)\n",
|
||||
"graph.add_edge(0, 5)\n",
|
||||
"graph.add_edge(1, 3)\n",
|
||||
"graph.add_edge(1, 4)\n",
|
||||
"graph.add_edge(2, 1)\n",
|
||||
"graph.add_edge(3, 2)\n",
|
||||
"graph.add_edge(3, 4)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Result:\n",
|
||||
"* search_path(start=0, end=2) -> [0, 1, 3, 2]\n",
|
||||
"* search_path(start=0, end=0) -> [0]\n",
|
||||
"* search_path(start=4, end=5) -> None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"To determine the shorted path in an unweighted graph, we can use breadth-first search keeping track of the previous nodes ids for each node. Previous nodes ids can be a dictionary of key: current node id and value: previous node id.\n",
|
||||
"\n",
|
||||
"* If the start node is the end node, return True\n",
|
||||
"* Add the start node to the queue and mark it as visited\n",
|
||||
" * Update the previous node ids, the previous node id of the start node is None\n",
|
||||
"* While the queue is not empty\n",
|
||||
" * Dequeue a node and visit it\n",
|
||||
" * If the node is the end node, return the previous nodes\n",
|
||||
" * Set the previous node to the current node\n",
|
||||
" * Iterate through each adjacent node\n",
|
||||
" * If the node has not been visited, add it to the queue and mark it as visited\n",
|
||||
" * Update the previous node ids\n",
|
||||
"* Return None\n",
|
||||
"\n",
|
||||
"Walk the previous node ids backwards to get the path.\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(V + E), where V = number of vertices and E = number of edges\n",
|
||||
"* Space: O(V + E)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../graph/graph.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from collections import deque\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class GraphShortestPath(Graph):\n",
|
||||
"\n",
|
||||
" def shortest_path(self, source_key, dest_key):\n",
|
||||
" if source_key is None or dest_key is None:\n",
|
||||
" return None\n",
|
||||
" if source_key is dest_key:\n",
|
||||
" return [source_key]\n",
|
||||
" prev_node_keys = self._shortest_path(source_key, dest_key)\n",
|
||||
" if prev_node_keys is None:\n",
|
||||
" return None\n",
|
||||
" else:\n",
|
||||
" path_ids = [dest_key]\n",
|
||||
" prev_node_key = prev_node_keys[dest_key]\n",
|
||||
" while prev_node_key is not None:\n",
|
||||
" path_ids.append(prev_node_key)\n",
|
||||
" prev_node_key = prev_node_keys[prev_node_key]\n",
|
||||
" return path_ids[::-1]\n",
|
||||
"\n",
|
||||
" def _shortest_path(self, source_key, dest_key):\n",
|
||||
" queue = deque()\n",
|
||||
" queue.append(self.nodes[source_key])\n",
|
||||
" prev_node_keys = {source_key: None}\n",
|
||||
" self.nodes[source_key].visit_state = State.visited\n",
|
||||
" while queue:\n",
|
||||
" node = queue.popleft()\n",
|
||||
" if node.key is dest_key:\n",
|
||||
" return prev_node_keys\n",
|
||||
" prev_node = node\n",
|
||||
" for adj_node in node.adj_nodes.values():\n",
|
||||
" if adj_node.visit_state == State.unvisited:\n",
|
||||
" queue.append(adj_node)\n",
|
||||
" prev_node_keys[adj_node.key] = prev_node.key\n",
|
||||
" adj_node.visit_state = State.visited\n",
|
||||
" return None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_shortest_path.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_shortest_path.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestShortestPath(object):\n",
|
||||
"\n",
|
||||
" def test_shortest_path(self):\n",
|
||||
" nodes = []\n",
|
||||
" graph = GraphShortestPath()\n",
|
||||
" for id in range(0, 6):\n",
|
||||
" nodes.append(graph.add_node(id))\n",
|
||||
" graph.add_edge(0, 1)\n",
|
||||
" graph.add_edge(0, 4)\n",
|
||||
" graph.add_edge(0, 5)\n",
|
||||
" graph.add_edge(1, 3)\n",
|
||||
" graph.add_edge(1, 4)\n",
|
||||
" graph.add_edge(2, 1)\n",
|
||||
" graph.add_edge(3, 2)\n",
|
||||
" graph.add_edge(3, 4)\n",
|
||||
"\n",
|
||||
" assert_equal(graph.shortest_path(nodes[0].key, nodes[2].key), [0, 1, 3, 2])\n",
|
||||
" assert_equal(graph.shortest_path(nodes[0].key, nodes[0].key), [0])\n",
|
||||
" assert_equal(graph.shortest_path(nodes[4].key, nodes[5].key), None)\n",
|
||||
"\n",
|
||||
" print('Success: test_shortest_path')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestShortestPath()\n",
|
||||
" test.test_shortest_path()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_shortest_path\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_shortest_path.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestShortestPath(object):
|
||||
|
||||
def test_shortest_path(self):
|
||||
nodes = []
|
||||
graph = GraphShortestPath()
|
||||
for id in range(0, 6):
|
||||
nodes.append(graph.add_node(id))
|
||||
graph.add_edge(0, 1)
|
||||
graph.add_edge(0, 4)
|
||||
graph.add_edge(0, 5)
|
||||
graph.add_edge(1, 3)
|
||||
graph.add_edge(1, 4)
|
||||
graph.add_edge(2, 1)
|
||||
graph.add_edge(3, 2)
|
||||
graph.add_edge(3, 4)
|
||||
|
||||
assert_equal(graph.shortest_path(nodes[0].key, nodes[2].key), [0, 1, 3, 2])
|
||||
assert_equal(graph.shortest_path(nodes[0].key, nodes[0].key), [0])
|
||||
assert_equal(graph.shortest_path(nodes[4].key, nodes[5].key), None)
|
||||
|
||||
print('Success: test_shortest_path')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestShortestPath()
|
||||
test.test_shortest_path()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
graphs_trees/invert_tree/__init__.py
Normal file
0
graphs_trees/invert_tree/__init__.py
Normal file
200
graphs_trees/invert_tree/invert_tree_challenge.ipynb
Normal file
200
graphs_trees/invert_tree/invert_tree_challenge.ipynb
Normal file
@ -0,0 +1,200 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Invert a binary tree.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* What does it mean to invert a binary tree?\n",
|
||||
" * Swap all left and right node pairs\n",
|
||||
"* Can we assume we already have a Node class?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"Input:\n",
|
||||
" 5\n",
|
||||
" / \\\n",
|
||||
" 2 7\n",
|
||||
" / \\ / \\\n",
|
||||
"1 3 6 9\n",
|
||||
"\n",
|
||||
"Output:\n",
|
||||
" 5\n",
|
||||
" / \\\n",
|
||||
" 7 2\n",
|
||||
" / \\ / \\\n",
|
||||
"9 6 3 1\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../bst/bst.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class InverseBst(Bst):\n",
|
||||
"\n",
|
||||
" def invert_tree(self):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_invert_tree.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestInvertTree(object):\n",
|
||||
"\n",
|
||||
" def test_invert_tree(self):\n",
|
||||
" root = Node(5)\n",
|
||||
" bst = InverseBst(root)\n",
|
||||
" node2 = bst.insert(2)\n",
|
||||
" node3 = bst.insert(3)\n",
|
||||
" node1 = bst.insert(1)\n",
|
||||
" node7 = bst.insert(7)\n",
|
||||
" node6 = bst.insert(6)\n",
|
||||
" node9 = bst.insert(9)\n",
|
||||
" result = bst.invert_tree()\n",
|
||||
" assert_equal(result, root)\n",
|
||||
" assert_equal(result.left, node7)\n",
|
||||
" assert_equal(result.right, node2)\n",
|
||||
" assert_equal(result.left.left, node9)\n",
|
||||
" assert_equal(result.left.right, node6)\n",
|
||||
" assert_equal(result.right.left, node3)\n",
|
||||
" assert_equal(result.right.right, node1)\n",
|
||||
" print('Success: test_invert_tree')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestInvertTree()\n",
|
||||
" test.test_invert_tree()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
229
graphs_trees/invert_tree/invert_tree_solution.ipynb
Normal file
229
graphs_trees/invert_tree/invert_tree_solution.ipynb
Normal file
@ -0,0 +1,229 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Invert a binary tree.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* What does it mean to invert a binary tree?\n",
|
||||
" * Swap all left and right node pairs\n",
|
||||
"* Can we assume we already have a Node class?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"Input:\n",
|
||||
" 5\n",
|
||||
" / \\\n",
|
||||
" 2 7\n",
|
||||
" / \\ / \\\n",
|
||||
"1 3 6 9\n",
|
||||
"\n",
|
||||
"Output:\n",
|
||||
" 5\n",
|
||||
" / \\\n",
|
||||
" 7 2\n",
|
||||
" / \\ / \\\n",
|
||||
"9 6 3 1\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"* Base case\n",
|
||||
" * If the root is None, return\n",
|
||||
"* Recursive case\n",
|
||||
" * Recurse on the left node\n",
|
||||
" * Recurse on the right node\n",
|
||||
" * Swap left and right\n",
|
||||
"* Return the node\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(h), where h is the height, for the recursion depth"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run ../bst/bst.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class InverseBst(Bst):\n",
|
||||
"\n",
|
||||
" def invert_tree(self):\n",
|
||||
" if self.root is None:\n",
|
||||
" raise TypeError('root cannot be None')\n",
|
||||
" return self._invert_tree(self.root)\n",
|
||||
"\n",
|
||||
" def _invert_tree(self, root):\n",
|
||||
" if root is None:\n",
|
||||
" return\n",
|
||||
" self._invert_tree(root.left)\n",
|
||||
" self._invert_tree(root.right)\n",
|
||||
" root.left, root.right = root.right, root.left\n",
|
||||
" return root"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_invert_tree.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_invert_tree.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestInvertTree(object):\n",
|
||||
"\n",
|
||||
" def test_invert_tree(self):\n",
|
||||
" root = Node(5)\n",
|
||||
" bst = InverseBst(root)\n",
|
||||
" node2 = bst.insert(2)\n",
|
||||
" node3 = bst.insert(3)\n",
|
||||
" node1 = bst.insert(1)\n",
|
||||
" node7 = bst.insert(7)\n",
|
||||
" node6 = bst.insert(6)\n",
|
||||
" node9 = bst.insert(9)\n",
|
||||
" result = bst.invert_tree()\n",
|
||||
" assert_equal(result, root)\n",
|
||||
" assert_equal(result.left, node7)\n",
|
||||
" assert_equal(result.right, node2)\n",
|
||||
" assert_equal(result.left.left, node9)\n",
|
||||
" assert_equal(result.left.right, node6)\n",
|
||||
" assert_equal(result.right.left, node3)\n",
|
||||
" assert_equal(result.right.right, node1)\n",
|
||||
" print('Success: test_invert_tree')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestInvertTree()\n",
|
||||
" test.test_invert_tree()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_invert_tree\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_invert_tree.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
32
graphs_trees/invert_tree/test_invert_tree.py
Normal file
32
graphs_trees/invert_tree/test_invert_tree.py
Normal file
@ -0,0 +1,32 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestInvertTree(object):
|
||||
|
||||
def test_invert_tree(self):
|
||||
root = Node(5)
|
||||
bst = InverseBst(root)
|
||||
node2 = bst.insert(2)
|
||||
node3 = bst.insert(3)
|
||||
node1 = bst.insert(1)
|
||||
node7 = bst.insert(7)
|
||||
node6 = bst.insert(6)
|
||||
node9 = bst.insert(9)
|
||||
result = bst.invert_tree()
|
||||
assert_equal(result, root)
|
||||
assert_equal(result.left, node7)
|
||||
assert_equal(result.right, node2)
|
||||
assert_equal(result.left.left, node9)
|
||||
assert_equal(result.left.right, node6)
|
||||
assert_equal(result.right.left, node3)
|
||||
assert_equal(result.right.right, node1)
|
||||
print('Success: test_invert_tree')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestInvertTree()
|
||||
test.test_invert_tree()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
graphs_trees/min_heap/__init__.py
Normal file
0
graphs_trees/min_heap/__init__.py
Normal file
66
graphs_trees/min_heap/min_heap.py
Normal file
66
graphs_trees/min_heap/min_heap.py
Normal file
@ -0,0 +1,66 @@
|
||||
from __future__ import division
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
class MinHeap(object):
|
||||
|
||||
def __init__(self):
|
||||
self.array = []
|
||||
|
||||
def __len__(self):
|
||||
return len(self.array)
|
||||
|
||||
def extract_min(self):
|
||||
if not self.array:
|
||||
return None
|
||||
if len(self.array) == 1:
|
||||
return self.array.pop(0)
|
||||
minimum = self.array[0]
|
||||
# Move the last element to the root
|
||||
self.array[0] = self.array.pop(-1)
|
||||
self._bubble_down(index=0)
|
||||
return minimum
|
||||
|
||||
def peek_min(self):
|
||||
return self.array[0] if self.array else None
|
||||
|
||||
def insert(self, key):
|
||||
if key is None:
|
||||
raise TypeError('key cannot be None')
|
||||
self.array.append(key)
|
||||
self._bubble_up(index=len(self.array)-1)
|
||||
|
||||
def _bubble_up(self, index):
|
||||
if index == 0:
|
||||
return
|
||||
index_parent = (index-1) // 2
|
||||
if self.array[index] < self.array[index_parent]:
|
||||
# Swap the indices and recurse
|
||||
self.array[index], self.array[index_parent] = \
|
||||
self.array[index_parent], self.array[index]
|
||||
self._bubble_up(index_parent)
|
||||
|
||||
def _bubble_down(self, index):
|
||||
min_child_index = self._find_smaller_child(index)
|
||||
if min_child_index == -1:
|
||||
return
|
||||
if self.array[index] > self.array[min_child_index]:
|
||||
# Swap the indices and recurse
|
||||
self.array[index], self.array[min_child_index] = \
|
||||
self.array[min_child_index], self.array[index]
|
||||
self._bubble_down(min_child_index)
|
||||
|
||||
def _find_smaller_child(self, index):
|
||||
left_child_index = 2 * index + 1
|
||||
right_child_index = 2 * index + 2
|
||||
if right_child_index >= len(self.array):
|
||||
if left_child_index >= len(self.array):
|
||||
return -1
|
||||
else:
|
||||
return left_child_index
|
||||
else:
|
||||
if self.array[left_child_index] < self.array[right_child_index]:
|
||||
return left_child_index
|
||||
else:
|
||||
return right_child_index
|
214
graphs_trees/min_heap/min_heap_challenge.ipynb
Normal file
214
graphs_trees/min_heap/min_heap_challenge.ipynb
Normal file
@ -0,0 +1,214 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement a min heap with extract_min and insert methods.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the inputs are ints?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* Extract min of an empty tree\n",
|
||||
"* Extract min general case\n",
|
||||
"* Insert into an empty tree\n",
|
||||
"* Insert general case (left and right insert)\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" _5_\n",
|
||||
" / \\\n",
|
||||
" 20 15\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 25\n",
|
||||
" \n",
|
||||
"extract_min(): 5\n",
|
||||
"\n",
|
||||
" _15_\n",
|
||||
" / \\\n",
|
||||
" 20 25\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 \n",
|
||||
"\n",
|
||||
"insert(2):\n",
|
||||
"\n",
|
||||
" _2_\n",
|
||||
" / \\\n",
|
||||
" 20 5\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 25 15\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/min_heap/min_heap_solution.ipynb). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class MinHeap(object):\n",
|
||||
"\n",
|
||||
" def __init__(self):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def extract_min(self):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass \n",
|
||||
"\n",
|
||||
" def peek_min(self):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def insert(self, data):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def _bubble_up(self, index):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_min_heap.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestMinHeap(object):\n",
|
||||
"\n",
|
||||
" def test_min_heap(self):\n",
|
||||
" heap = MinHeap()\n",
|
||||
" assert_equal(heap.peek_min(), None)\n",
|
||||
" assert_equal(heap.extract_min(), None)\n",
|
||||
" heap.insert(20)\n",
|
||||
" assert_equal(heap.peek_min(), 20)\n",
|
||||
" heap.insert(5)\n",
|
||||
" assert_equal(heap.peek_min(), 5)\n",
|
||||
" heap.insert(15)\n",
|
||||
" heap.insert(22)\n",
|
||||
" heap.insert(40)\n",
|
||||
" heap.insert(5)\n",
|
||||
" assert_equal(heap.peek_min(), 5)\n",
|
||||
" heap.insert(3)\n",
|
||||
" assert_equal(heap.peek_min(), 3)\n",
|
||||
" assert_equal(heap.extract_min(), 3)\n",
|
||||
" assert_equal(heap.peek_min(), 5)\n",
|
||||
" print('Success: test_min_heap')\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"def main():\n",
|
||||
" test = TestMinHeap()\n",
|
||||
" test.test_min_heap()\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/min_heap/min_heap_solution.ipynb) for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
411
graphs_trees/min_heap/min_heap_solution.ipynb
Normal file
411
graphs_trees/min_heap/min_heap_solution.ipynb
Normal file
@ -0,0 +1,411 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement a min heap with extract_min and insert methods.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the inputs are ints?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* Extract min of an empty tree\n",
|
||||
"* Extract min general case\n",
|
||||
"* Insert into an empty tree\n",
|
||||
"* Insert general case (left and right insert)\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" _5_\n",
|
||||
" / \\\n",
|
||||
" 20 15\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 25\n",
|
||||
" \n",
|
||||
"extract_min(): 5\n",
|
||||
"\n",
|
||||
" _15_\n",
|
||||
" / \\\n",
|
||||
" 20 25\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 \n",
|
||||
"\n",
|
||||
"insert(2):\n",
|
||||
"\n",
|
||||
" _2_\n",
|
||||
" / \\\n",
|
||||
" 20 5\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 25 15\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"A heap is a complete binary tree where each node is smaller than its children.\n",
|
||||
"\n",
|
||||
"### extract_min\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" _5_\n",
|
||||
" / \\\n",
|
||||
" 20 15\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 25\n",
|
||||
"\n",
|
||||
"Save the root as the value to be returned: 5\n",
|
||||
"Move the right most element to the root: 25\n",
|
||||
"\n",
|
||||
" _25_\n",
|
||||
" / \\\n",
|
||||
" 20 15\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 \n",
|
||||
"\n",
|
||||
"Bubble down 25: Swap 25 and 15 (the smaller child)\n",
|
||||
"\n",
|
||||
" _15_\n",
|
||||
" / \\\n",
|
||||
" 20 25\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 \n",
|
||||
"\n",
|
||||
"Return 5\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"We'll use an array to represent the tree, here are the indices:\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" _0_\n",
|
||||
" / \\\n",
|
||||
" 1 2\n",
|
||||
" / \\ / \\\n",
|
||||
" 3 4 \n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"To get to a child, we take 2 * index + 1 (left child) or 2 * index + 2 (right child).\n",
|
||||
"\n",
|
||||
"For example, the right child of index 1 is 2 * 1 + 2 = 4.\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(lg(n))\n",
|
||||
"* Space: O(lg(n)) for the recursion depth (tree height), or O(1) if using an iterative approach\n",
|
||||
"\n",
|
||||
"### insert\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" _5_\n",
|
||||
" / \\\n",
|
||||
" 20 15\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 25\n",
|
||||
"\n",
|
||||
"insert(2):\n",
|
||||
"Insert at the right-most spot to maintain the heap property.\n",
|
||||
"\n",
|
||||
" _5_\n",
|
||||
" / \\\n",
|
||||
" 20 15\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 25 2\n",
|
||||
"\n",
|
||||
"Bubble up 2: Swap 2 and 15\n",
|
||||
"\n",
|
||||
" _5_\n",
|
||||
" / \\\n",
|
||||
" 20 2\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 25 15\n",
|
||||
"\n",
|
||||
"Bubble up 2: Swap 2 and 5\n",
|
||||
"\n",
|
||||
" _2_\n",
|
||||
" / \\\n",
|
||||
" 20 5\n",
|
||||
" / \\ / \\\n",
|
||||
" 22 40 25 15\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"We'll use an array to represent the tree, here are the indices:\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" _0_\n",
|
||||
" / \\\n",
|
||||
" 1 2\n",
|
||||
" / \\ / \\\n",
|
||||
" 3 4 5 6\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"To get to a parent, we take (index - 1) // 2. \n",
|
||||
"\n",
|
||||
"For example, the parent of index 6 is (6 - 1) // 2 = 2.\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(lg(n))\n",
|
||||
"* Space: O(lg(n)) for the recursion depth (tree height), or O(1) if using an iterative approach"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting min_heap.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile min_heap.py\n",
|
||||
"from __future__ import division\n",
|
||||
"\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class MinHeap(object):\n",
|
||||
"\n",
|
||||
" def __init__(self):\n",
|
||||
" self.array = []\n",
|
||||
"\n",
|
||||
" def __len__(self):\n",
|
||||
" return len(self.array)\n",
|
||||
"\n",
|
||||
" def extract_min(self):\n",
|
||||
" if not self.array:\n",
|
||||
" return None\n",
|
||||
" if len(self.array) == 1:\n",
|
||||
" return self.array.pop(0)\n",
|
||||
" minimum = self.array[0]\n",
|
||||
" # Move the last element to the root\n",
|
||||
" self.array[0] = self.array.pop(-1)\n",
|
||||
" self._bubble_down(index=0)\n",
|
||||
" return minimum\n",
|
||||
"\n",
|
||||
" def peek_min(self):\n",
|
||||
" return self.array[0] if self.array else None\n",
|
||||
"\n",
|
||||
" def insert(self, key):\n",
|
||||
" if key is None:\n",
|
||||
" raise TypeError('key cannot be None')\n",
|
||||
" self.array.append(key)\n",
|
||||
" self._bubble_up(index=len(self.array) - 1)\n",
|
||||
"\n",
|
||||
" def _bubble_up(self, index):\n",
|
||||
" if index == 0:\n",
|
||||
" return\n",
|
||||
" index_parent = (index - 1) // 2\n",
|
||||
" if self.array[index] < self.array[index_parent]:\n",
|
||||
" # Swap the indices and recurse\n",
|
||||
" self.array[index], self.array[index_parent] = \\\n",
|
||||
" self.array[index_parent], self.array[index]\n",
|
||||
" self._bubble_up(index_parent)\n",
|
||||
"\n",
|
||||
" def _bubble_down(self, index):\n",
|
||||
" min_child_index = self._find_smaller_child(index)\n",
|
||||
" if min_child_index == -1:\n",
|
||||
" return\n",
|
||||
" if self.array[index] > self.array[min_child_index]:\n",
|
||||
" # Swap the indices and recurse\n",
|
||||
" self.array[index], self.array[min_child_index] = \\\n",
|
||||
" self.array[min_child_index], self.array[index]\n",
|
||||
" self._bubble_down(min_child_index)\n",
|
||||
"\n",
|
||||
" def _find_smaller_child(self, index):\n",
|
||||
" left_child_index = 2 * index + 1\n",
|
||||
" right_child_index = 2 * index + 2\n",
|
||||
" # No right child\n",
|
||||
" if right_child_index >= len(self.array):\n",
|
||||
" # No left child\n",
|
||||
" if left_child_index >= len(self.array):\n",
|
||||
" return -1\n",
|
||||
" # Left child only\n",
|
||||
" else:\n",
|
||||
" return left_child_index\n",
|
||||
" else:\n",
|
||||
" # Compare left and right children\n",
|
||||
" if self.array[left_child_index] < self.array[right_child_index]:\n",
|
||||
" return left_child_index\n",
|
||||
" else:\n",
|
||||
" return right_child_index"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run min_heap.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_min_heap.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_min_heap.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestMinHeap(object):\n",
|
||||
"\n",
|
||||
" def test_min_heap(self):\n",
|
||||
" heap = MinHeap()\n",
|
||||
" assert_equal(heap.peek_min(), None)\n",
|
||||
" assert_equal(heap.extract_min(), None)\n",
|
||||
" heap.insert(20)\n",
|
||||
" assert_equal(heap.array[0], 20)\n",
|
||||
" heap.insert(5)\n",
|
||||
" assert_equal(heap.array[0], 5)\n",
|
||||
" assert_equal(heap.array[1], 20)\n",
|
||||
" heap.insert(15)\n",
|
||||
" assert_equal(heap.array[0], 5)\n",
|
||||
" assert_equal(heap.array[1], 20)\n",
|
||||
" assert_equal(heap.array[2], 15)\n",
|
||||
" heap.insert(22)\n",
|
||||
" assert_equal(heap.array[0], 5)\n",
|
||||
" assert_equal(heap.array[1], 20)\n",
|
||||
" assert_equal(heap.array[2], 15)\n",
|
||||
" assert_equal(heap.array[3], 22)\n",
|
||||
" heap.insert(40)\n",
|
||||
" assert_equal(heap.array[0], 5)\n",
|
||||
" assert_equal(heap.array[1], 20)\n",
|
||||
" assert_equal(heap.array[2], 15)\n",
|
||||
" assert_equal(heap.array[3], 22)\n",
|
||||
" assert_equal(heap.array[4], 40)\n",
|
||||
" heap.insert(3)\n",
|
||||
" assert_equal(heap.array[0], 3)\n",
|
||||
" assert_equal(heap.array[1], 20)\n",
|
||||
" assert_equal(heap.array[2], 5)\n",
|
||||
" assert_equal(heap.array[3], 22)\n",
|
||||
" assert_equal(heap.array[4], 40)\n",
|
||||
" assert_equal(heap.array[5], 15)\n",
|
||||
" mins = []\n",
|
||||
" while heap:\n",
|
||||
" mins.append(heap.extract_min())\n",
|
||||
" assert_equal(mins, [3, 5, 15, 20, 22, 40])\n",
|
||||
" print('Success: test_min_heap')\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"def main():\n",
|
||||
" test = TestMinHeap()\n",
|
||||
" test.test_min_heap()\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_min_heap\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_min_heap.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
50
graphs_trees/min_heap/test_min_heap.py
Normal file
50
graphs_trees/min_heap/test_min_heap.py
Normal file
@ -0,0 +1,50 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestMinHeap(object):
|
||||
|
||||
def test_min_heap(self):
|
||||
heap = MinHeap()
|
||||
assert_equal(heap.peek_min(), None)
|
||||
assert_equal(heap.extract_min(), None)
|
||||
heap.insert(20)
|
||||
assert_equal(heap.array[0], 20)
|
||||
heap.insert(5)
|
||||
assert_equal(heap.array[0], 5)
|
||||
assert_equal(heap.array[1], 20)
|
||||
heap.insert(15)
|
||||
assert_equal(heap.array[0], 5)
|
||||
assert_equal(heap.array[1], 20)
|
||||
assert_equal(heap.array[2], 15)
|
||||
heap.insert(22)
|
||||
assert_equal(heap.array[0], 5)
|
||||
assert_equal(heap.array[1], 20)
|
||||
assert_equal(heap.array[2], 15)
|
||||
assert_equal(heap.array[3], 22)
|
||||
heap.insert(40)
|
||||
assert_equal(heap.array[0], 5)
|
||||
assert_equal(heap.array[1], 20)
|
||||
assert_equal(heap.array[2], 15)
|
||||
assert_equal(heap.array[3], 22)
|
||||
assert_equal(heap.array[4], 40)
|
||||
heap.insert(3)
|
||||
assert_equal(heap.array[0], 3)
|
||||
assert_equal(heap.array[1], 20)
|
||||
assert_equal(heap.array[2], 5)
|
||||
assert_equal(heap.array[3], 22)
|
||||
assert_equal(heap.array[4], 40)
|
||||
assert_equal(heap.array[5], 15)
|
||||
mins = []
|
||||
while heap:
|
||||
mins.append(heap.extract_min())
|
||||
assert_equal(mins, [3, 5, 15, 20, 22, 40])
|
||||
print('Success: test_min_heap')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestMinHeap()
|
||||
test.test_min_heap()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
graphs_trees/tree_lca/__init__.py
Normal file
0
graphs_trees/tree_lca/__init__.py
Normal file
45
graphs_trees/tree_lca/test_lca.py
Normal file
45
graphs_trees/tree_lca/test_lca.py
Normal file
@ -0,0 +1,45 @@
|
||||
from nose.tools import assert_equal
|
||||
|
||||
|
||||
class TestLowestCommonAncestor(object):
|
||||
|
||||
def test_lca(self):
|
||||
node10 = Node(10)
|
||||
node5 = Node(5)
|
||||
node12 = Node(12)
|
||||
node3 = Node(3)
|
||||
node1 = Node(1)
|
||||
node8 = Node(8)
|
||||
node9 = Node(9)
|
||||
node18 = Node(18)
|
||||
node20 = Node(20)
|
||||
node40 = Node(40)
|
||||
node3.left = node1
|
||||
node3.right = node8
|
||||
node5.left = node12
|
||||
node5.right = node3
|
||||
node20.left = node40
|
||||
node9.left = node18
|
||||
node9.right = node20
|
||||
node10.left = node5
|
||||
node10.right = node9
|
||||
root = node10
|
||||
node0 = Node(0)
|
||||
binary_tree = BinaryTree()
|
||||
assert_equal(binary_tree.lca(root, node0, node5), None)
|
||||
assert_equal(binary_tree.lca(root, node5, node0), None)
|
||||
assert_equal(binary_tree.lca(root, node1, node8), node3)
|
||||
assert_equal(binary_tree.lca(root, node12, node8), node5)
|
||||
assert_equal(binary_tree.lca(root, node12, node40), node10)
|
||||
assert_equal(binary_tree.lca(root, node9, node20), node9)
|
||||
assert_equal(binary_tree.lca(root, node3, node5), node5)
|
||||
print('Success: test_lca')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestLowestCommonAncestor()
|
||||
test.test_lca()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
221
graphs_trees/tree_lca/tree_lca_challenge.ipynb
Normal file
221
graphs_trees/tree_lca/tree_lca_challenge.ipynb
Normal file
@ -0,0 +1,221 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the lowest common ancestor in a binary tree.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is this a binary search tree?\n",
|
||||
" * No\n",
|
||||
"* Can we assume the two nodes are in the tree?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" _10_\n",
|
||||
" / \\\n",
|
||||
" 5 9\n",
|
||||
" / \\ / \\\n",
|
||||
" 12 3 18 20\n",
|
||||
" / \\ /\n",
|
||||
" 1 8 40\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"* 0, 5 -> None\n",
|
||||
"* 5, 0 -> None\n",
|
||||
"* 1, 8 -> 3\n",
|
||||
"* 12, 8 -> 5\n",
|
||||
"* 12, 40 -> 10\n",
|
||||
"* 9, 20 -> 9\n",
|
||||
"* 3, 5 -> 5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Node(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, key, left=None, right=None):\n",
|
||||
" self.key = key\n",
|
||||
" self.left = left\n",
|
||||
" self.right = right\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return str(self.key)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class BinaryTree(object):\n",
|
||||
"\n",
|
||||
" def lca(self, root, node1, node2):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_lca.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestLowestCommonAncestor(object):\n",
|
||||
"\n",
|
||||
" def test_lca(self):\n",
|
||||
" node10 = Node(10)\n",
|
||||
" node5 = Node(5)\n",
|
||||
" node12 = Node(12)\n",
|
||||
" node3 = Node(3)\n",
|
||||
" node1 = Node(1)\n",
|
||||
" node8 = Node(8)\n",
|
||||
" node9 = Node(9)\n",
|
||||
" node18 = Node(18)\n",
|
||||
" node20 = Node(20)\n",
|
||||
" node40 = Node(40)\n",
|
||||
" node3.left = node1\n",
|
||||
" node3.right = node8\n",
|
||||
" node5.left = node12\n",
|
||||
" node5.right = node3\n",
|
||||
" node20.left = node40\n",
|
||||
" node9.left = node18\n",
|
||||
" node9.right = node20\n",
|
||||
" node10.left = node5\n",
|
||||
" node10.right = node9\n",
|
||||
" root = node10\n",
|
||||
" node0 = Node(0)\n",
|
||||
" binary_tree = BinaryTree()\n",
|
||||
" assert_equal(binary_tree.lca(root, node0, node5), None)\n",
|
||||
" assert_equal(binary_tree.lca(root, node5, node0), None)\n",
|
||||
" assert_equal(binary_tree.lca(root, node1, node8), node3)\n",
|
||||
" assert_equal(binary_tree.lca(root, node12, node8), node5)\n",
|
||||
" assert_equal(binary_tree.lca(root, node12, node40), node10)\n",
|
||||
" assert_equal(binary_tree.lca(root, node9, node20), node9)\n",
|
||||
" assert_equal(binary_tree.lca(root, node3, node5), node5)\n",
|
||||
" print('Success: test_lca')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestLowestCommonAncestor()\n",
|
||||
" test.test_lca()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
314
graphs_trees/tree_lca/tree_lca_solution.ipynb
Normal file
314
graphs_trees/tree_lca/tree_lca_solution.ipynb
Normal file
@ -0,0 +1,314 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Find the lowest common ancestor of two nodes in a binary tree.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is this a binary search tree?\n",
|
||||
" * No\n",
|
||||
"* Can we assume the two nodes are in the tree?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
" _10_\n",
|
||||
" / \\\n",
|
||||
" 5 9\n",
|
||||
" / \\ / \\\n",
|
||||
" 12 3 18 20\n",
|
||||
" / \\ /\n",
|
||||
" 1 8 40\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"* 0, 5 -> None\n",
|
||||
"* 5, 0 -> None\n",
|
||||
"* 1, 8 -> 3\n",
|
||||
"* 12, 8 -> 5\n",
|
||||
"* 12, 40 -> 10\n",
|
||||
"* 9, 20 -> 9\n",
|
||||
"* 3, 5 -> 5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"* Verify both nodes are in the tree\n",
|
||||
"* Base cases\n",
|
||||
" * If the root is None, return None\n",
|
||||
" * If the root is either node, return the root\n",
|
||||
"* Recursively search left and right\n",
|
||||
"* If the left and right are both nodes\n",
|
||||
" * The return the root\n",
|
||||
"* Else, left or right, whichever is valid\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(h), where h is the height of the tree\n",
|
||||
"* Space: O(h), where h is the recursion depth"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Node(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, key, left=None, right=None):\n",
|
||||
" self.key = key\n",
|
||||
" self.left = left\n",
|
||||
" self.right = right\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return str(self.key)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class BinaryTree(object):\n",
|
||||
"\n",
|
||||
" def lca(self, root, node1, node2):\n",
|
||||
" if None in (root, node1, node2):\n",
|
||||
" return None\n",
|
||||
" if (not self._node_in_tree(root, node1) or\n",
|
||||
" not self._node_in_tree(root, node2)):\n",
|
||||
" return None\n",
|
||||
" return self._lca(root, node1, node2)\n",
|
||||
"\n",
|
||||
" def _node_in_tree(self, root, node):\n",
|
||||
" if root is None:\n",
|
||||
" return False\n",
|
||||
" if root is node:\n",
|
||||
" return True\n",
|
||||
" left = self._node_in_tree(root.left, node)\n",
|
||||
" right = self._node_in_tree(root.right, node)\n",
|
||||
" return left or right\n",
|
||||
"\n",
|
||||
" def _lca(self, root, node1, node2):\n",
|
||||
" if root is None:\n",
|
||||
" return None\n",
|
||||
" if root is node1 or root is node2:\n",
|
||||
" return root\n",
|
||||
" left_node = self._lca(root.left, node1, node2)\n",
|
||||
" right_node = self._lca(root.right, node1, node2)\n",
|
||||
" if left_node is not None and right_node is not None:\n",
|
||||
" return root\n",
|
||||
" else:\n",
|
||||
" return left_node if left_node is not None else right_node"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class LcaResult(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, node, is_ancestor):\n",
|
||||
" self.node = node\n",
|
||||
" self.is_ancestor = is_ancestor\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class BinaryTreeOptimized(object):\n",
|
||||
"\n",
|
||||
" def lca(self, root, node1, node2):\n",
|
||||
" if root is None:\n",
|
||||
" raise TypeError('root cannot be None')\n",
|
||||
" result = self._lca(root, node1, node2)\n",
|
||||
" if result.is_ancestor:\n",
|
||||
" return result.node\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
" def _lca(self, curr_node, node1, node2):\n",
|
||||
" if curr_node is None:\n",
|
||||
" return LcaResult(None, is_ancestor=False)\n",
|
||||
" if curr_node is node1 and curr_node is node2:\n",
|
||||
" return LcaResult(curr_node, is_ancestor=True)\n",
|
||||
" left_result = self._lca(curr_node.left, node1, node2)\n",
|
||||
" if left_result.is_ancestor:\n",
|
||||
" return left_result\n",
|
||||
" right_result = self._lca(curr_node.right, node1, node2)\n",
|
||||
" if right_result.is_ancestor:\n",
|
||||
" return right_result\n",
|
||||
" if left_result.node is not None and right_result.node is not None:\n",
|
||||
" return LcaResult(curr_node, is_ancestor=True)\n",
|
||||
" elif curr_node is node1 or curr_node is node2:\n",
|
||||
" is_ancestor = left_result.node is not None or \\\n",
|
||||
" right_result.node is not None\n",
|
||||
" return LcaResult(curr_node, is_ancestor)\n",
|
||||
" else:\n",
|
||||
" return LcaResult(left_result.node if left_result.node is not None \\\n",
|
||||
" else right_result.node, is_ancestor=False)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_lca.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_lca.py\n",
|
||||
"from nose.tools import assert_equal\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestLowestCommonAncestor(object):\n",
|
||||
"\n",
|
||||
" def test_lca(self):\n",
|
||||
" node10 = Node(10)\n",
|
||||
" node5 = Node(5)\n",
|
||||
" node12 = Node(12)\n",
|
||||
" node3 = Node(3)\n",
|
||||
" node1 = Node(1)\n",
|
||||
" node8 = Node(8)\n",
|
||||
" node9 = Node(9)\n",
|
||||
" node18 = Node(18)\n",
|
||||
" node20 = Node(20)\n",
|
||||
" node40 = Node(40)\n",
|
||||
" node3.left = node1\n",
|
||||
" node3.right = node8\n",
|
||||
" node5.left = node12\n",
|
||||
" node5.right = node3\n",
|
||||
" node20.left = node40\n",
|
||||
" node9.left = node18\n",
|
||||
" node9.right = node20\n",
|
||||
" node10.left = node5\n",
|
||||
" node10.right = node9\n",
|
||||
" root = node10\n",
|
||||
" node0 = Node(0)\n",
|
||||
" binary_tree = BinaryTree()\n",
|
||||
" assert_equal(binary_tree.lca(root, node0, node5), None)\n",
|
||||
" assert_equal(binary_tree.lca(root, node5, node0), None)\n",
|
||||
" assert_equal(binary_tree.lca(root, node1, node8), node3)\n",
|
||||
" assert_equal(binary_tree.lca(root, node12, node8), node5)\n",
|
||||
" assert_equal(binary_tree.lca(root, node12, node40), node10)\n",
|
||||
" assert_equal(binary_tree.lca(root, node9, node20), node9)\n",
|
||||
" assert_equal(binary_tree.lca(root, node3, node5), node5)\n",
|
||||
" print('Success: test_lca')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestLowestCommonAncestor()\n",
|
||||
" test.test_lca()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_lca\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_lca.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
0
graphs_trees/trie/__init__.py
Normal file
0
graphs_trees/trie/__init__.py
Normal file
74
graphs_trees/trie/test_trie.py
Normal file
74
graphs_trees/trie/test_trie.py
Normal file
@ -0,0 +1,74 @@
|
||||
from nose.tools import assert_true
|
||||
from nose.tools import raises
|
||||
|
||||
|
||||
class TestTrie(object):
|
||||
|
||||
def test_trie(self):
|
||||
trie = Trie()
|
||||
|
||||
print('Test: Insert')
|
||||
words = ['a', 'at', 'has', 'hat', 'he',
|
||||
'me', 'men', 'mens', 'met']
|
||||
for word in words:
|
||||
trie.insert(word)
|
||||
for word in trie.list_words():
|
||||
assert_true(trie.find(word) is not None)
|
||||
|
||||
print('Test: Remove me')
|
||||
trie.remove('me')
|
||||
words_removed = ['me']
|
||||
words = ['a', 'at', 'has', 'hat', 'he',
|
||||
'men', 'mens', 'met']
|
||||
for word in words:
|
||||
assert_true(trie.find(word) is not None)
|
||||
for word in words_removed:
|
||||
assert_true(trie.find(word) is None)
|
||||
|
||||
print('Test: Remove mens')
|
||||
trie.remove('mens')
|
||||
words_removed = ['me', 'mens']
|
||||
words = ['a', 'at', 'has', 'hat', 'he',
|
||||
'men', 'met']
|
||||
for word in words:
|
||||
assert_true(trie.find(word) is not None)
|
||||
for word in words_removed:
|
||||
assert_true(trie.find(word) is None)
|
||||
|
||||
print('Test: Remove a')
|
||||
trie.remove('a')
|
||||
words_removed = ['a', 'me', 'mens']
|
||||
words = ['at', 'has', 'hat', 'he',
|
||||
'men', 'met']
|
||||
for word in words:
|
||||
assert_true(trie.find(word) is not None)
|
||||
for word in words_removed:
|
||||
assert_true(trie.find(word) is None)
|
||||
|
||||
print('Test: Remove has')
|
||||
trie.remove('has')
|
||||
words_removed = ['a', 'has', 'me', 'mens']
|
||||
words = ['at', 'hat', 'he',
|
||||
'men', 'met']
|
||||
for word in words:
|
||||
assert_true(trie.find(word) is not None)
|
||||
for word in words_removed:
|
||||
assert_true(trie.find(word) is None)
|
||||
|
||||
print('Success: test_trie')
|
||||
|
||||
@raises(Exception)
|
||||
def test_trie_remove_invalid(self):
|
||||
print('Test: Remove from empty trie')
|
||||
trie = Trie()
|
||||
assert_true(trie.remove('foo') is None)
|
||||
|
||||
|
||||
def main():
|
||||
test = TestTrie()
|
||||
test.test_trie()
|
||||
test.test_trie_remove_invalid()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
76
graphs_trees/trie/trie.py
Normal file
76
graphs_trees/trie/trie.py
Normal file
@ -0,0 +1,76 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
class Node(object):
|
||||
|
||||
def __init__(self, key, parent=None, terminates=False):
|
||||
self.key = key
|
||||
self.terminates = False
|
||||
self.parent = parent
|
||||
self.children = {}
|
||||
|
||||
|
||||
class Trie(object):
|
||||
|
||||
def __init__(self):
|
||||
self.root = Node('')
|
||||
|
||||
def find(self, word):
|
||||
if word is None:
|
||||
raise TypeError('word cannot be None')
|
||||
node = self.root
|
||||
for char in word:
|
||||
if char in node.children:
|
||||
node = node.children[char]
|
||||
else:
|
||||
return None
|
||||
return node if node.terminates else None
|
||||
|
||||
def insert(self, word):
|
||||
if word is None:
|
||||
raise TypeError('word cannot be None')
|
||||
node = self.root
|
||||
parent = None
|
||||
for char in word:
|
||||
if char in node.children:
|
||||
node = node.children[char]
|
||||
else:
|
||||
node.children[char] = Node(char, parent=node)
|
||||
node = node.children[char]
|
||||
node.terminates = True
|
||||
|
||||
def remove(self, word):
|
||||
if word is None:
|
||||
raise TypeError('word cannot be None')
|
||||
node = self.find(word)
|
||||
if node is None:
|
||||
raise KeyError('word does not exist')
|
||||
node.terminates = False
|
||||
parent = node.parent
|
||||
while parent is not None:
|
||||
# As we are propagating the delete up the
|
||||
# parents, if this node has children, stop
|
||||
# here to prevent orphaning its children.
|
||||
# Or
|
||||
# if this node is a terminating node that is
|
||||
# not the terminating node of the input word,
|
||||
# stop to prevent removing the associated word.
|
||||
if node.children or node.terminates:
|
||||
return
|
||||
del parent.children[node.key]
|
||||
node = parent
|
||||
parent = parent.parent
|
||||
|
||||
def list_words(self):
|
||||
result = []
|
||||
curr_word = ''
|
||||
self._list_words(self.root, curr_word, result)
|
||||
return result
|
||||
|
||||
def _list_words(self, node, curr_word, result):
|
||||
if node is None:
|
||||
return
|
||||
for key, child in node.children.items():
|
||||
if child.terminates:
|
||||
result.append(curr_word+key)
|
||||
self._list_words(child, curr_word+key, result)
|
279
graphs_trees/trie/trie_challenge.ipynb
Normal file
279
graphs_trees/trie/trie_challenge.ipynb
Normal file
@ -0,0 +1,279 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement a trie with find, insert, remove, and list_words methods.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume we are working with strings?\n",
|
||||
" * Yes\n",
|
||||
"* Are the strings in ASCII?\n",
|
||||
" * Yes\n",
|
||||
"* Should `find` only match exact words with a terminating character?\n",
|
||||
" * Yes\n",
|
||||
"* Should `list_words` only return words with a terminating character?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"\n",
|
||||
" root\n",
|
||||
" / | \\\n",
|
||||
" h a* m\n",
|
||||
" / \\ \\ \\\n",
|
||||
" a e* t* e*\n",
|
||||
" / \\ / \\\n",
|
||||
" s* t* n* t*\n",
|
||||
" /\n",
|
||||
" s*\n",
|
||||
"\n",
|
||||
"find\n",
|
||||
"\n",
|
||||
"* Find on an empty trie\n",
|
||||
"* Find non-matching\n",
|
||||
"* Find matching\n",
|
||||
"\n",
|
||||
"insert\n",
|
||||
"\n",
|
||||
"* Insert on empty trie\n",
|
||||
"* Insert to make a leaf terminator char\n",
|
||||
"* Insert to extend an existing terminator char\n",
|
||||
"\n",
|
||||
"remove\n",
|
||||
"\n",
|
||||
"* Remove me\n",
|
||||
"* Remove mens\n",
|
||||
"* Remove a\n",
|
||||
"* Remove has\n",
|
||||
"\n",
|
||||
"list_words\n",
|
||||
"\n",
|
||||
"* List empty\n",
|
||||
"* List general case\n",
|
||||
"</pre>\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/trie/trie_solution.ipynb). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from collections import OrderedDict\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Node(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, data, parent=None, terminates=False):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Trie(object):\n",
|
||||
"\n",
|
||||
" def __init__(self):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def find(self, word):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def insert(self, word):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def remove(self, word):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def list_words(self):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_trie.py\n",
|
||||
"from nose.tools import assert_true\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestTrie(object):\n",
|
||||
"\n",
|
||||
" def test_trie(self):\n",
|
||||
" print('Test: Remove from empty trie')\n",
|
||||
" trie = Trie()\n",
|
||||
" assert_true(trie.remove('foo') is None)\n",
|
||||
"\n",
|
||||
" print('Test: Insert')\n",
|
||||
" words = ['a', 'at', 'has', 'hat', 'he',\n",
|
||||
" 'me', 'men', 'mens', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" trie.insert(word)\n",
|
||||
" for word in trie.list_words():\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
"\n",
|
||||
" # Remove me\n",
|
||||
" # Remove mens\n",
|
||||
" # Remove a\n",
|
||||
" \n",
|
||||
" print('Test: Remove me')\n",
|
||||
" trie.remove('me')\n",
|
||||
" words_removed = ['me']\n",
|
||||
" words = ['a', 'at', 'has', 'hat', 'he',\n",
|
||||
" 'men', 'mens', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
" for word in words_removed:\n",
|
||||
" assert_true(trie.find(word) is None)\n",
|
||||
"\n",
|
||||
" print('Test: Remove mens')\n",
|
||||
" trie.remove('mens')\n",
|
||||
" words_removed = ['me', 'mens']\n",
|
||||
" words = ['a', 'at', 'has', 'hat', 'he',\n",
|
||||
" 'men', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
" for word in words_removed:\n",
|
||||
" assert_true(trie.find(word) is None)\n",
|
||||
"\n",
|
||||
" print('Test: Remove a')\n",
|
||||
" trie.remove('a')\n",
|
||||
" words_removed = ['a', 'me', 'mens']\n",
|
||||
" words = ['at', 'has', 'hat', 'he',\n",
|
||||
" 'men', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
" for word in words_removed:\n",
|
||||
" assert_true(trie.find(word) is None)\n",
|
||||
"\n",
|
||||
" print('Test: Remove has')\n",
|
||||
" trie.remove('has')\n",
|
||||
" words_removed = ['a', 'has', 'me', 'mens']\n",
|
||||
" words = ['at', 'hat', 'he',\n",
|
||||
" 'men', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
" for word in words_removed:\n",
|
||||
" assert_true(trie.find(word) is None)\n",
|
||||
"\n",
|
||||
" print('Success: test_trie')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestTrie()\n",
|
||||
" test.test_trie()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/trie/trie_solution.ipynb) for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
418
graphs_trees/trie/trie_solution.ipynb
Normal file
418
graphs_trees/trie/trie_solution.ipynb
Normal file
@ -0,0 +1,418 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Implement a trie with find, insert, remove, and list_words methods.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume we are working with strings?\n",
|
||||
" * Yes\n",
|
||||
"* Are the strings in ASCII?\n",
|
||||
" * Yes\n",
|
||||
"* Should `find` only match exact words with a terminating character?\n",
|
||||
" * Yes\n",
|
||||
"* Should `list_words` only return words with a terminating character?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"\n",
|
||||
"root node is denoted by ''\n",
|
||||
"\n",
|
||||
" ''\n",
|
||||
" / | \\\n",
|
||||
" h a* m\n",
|
||||
" / \\ \\ \\\n",
|
||||
" a e* t* e*\n",
|
||||
" / \\ / \\\n",
|
||||
" s* t* n* t*\n",
|
||||
" /\n",
|
||||
" s*\n",
|
||||
"\n",
|
||||
"find\n",
|
||||
"\n",
|
||||
"* Find on an empty trie\n",
|
||||
"* Find non-matching\n",
|
||||
"* Find matching\n",
|
||||
"\n",
|
||||
"insert\n",
|
||||
"\n",
|
||||
"* Insert on empty trie\n",
|
||||
"* Insert to make a leaf terminator char\n",
|
||||
"* Insert to extend an existing terminator char\n",
|
||||
"\n",
|
||||
"remove\n",
|
||||
"\n",
|
||||
"* Remove me\n",
|
||||
"* Remove mens\n",
|
||||
"* Remove a\n",
|
||||
"* Remove has\n",
|
||||
"\n",
|
||||
"list_words\n",
|
||||
"\n",
|
||||
"* List empty\n",
|
||||
"* List general case\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"### find\n",
|
||||
"\n",
|
||||
"* Set node to the root\n",
|
||||
"* For each char in the input word\n",
|
||||
" * Check the current node's children to see if it contains the char\n",
|
||||
" * If a child has the char, set node to the child\n",
|
||||
" * Else, return None\n",
|
||||
"* Return the last child node if it has a terminator, else None\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(m), where m is the length of the word\n",
|
||||
"* Space: O(h) for the recursion depth (tree height), or O(1) if using an iterative approach\n",
|
||||
"\n",
|
||||
"### insert\n",
|
||||
"\n",
|
||||
"* set node to the root\n",
|
||||
"* For each char in the input word\n",
|
||||
" * Check the current node's children to see if it contains the char\n",
|
||||
" * If a child has the char, set node to the child\n",
|
||||
" * Else, insert a new node with the char\n",
|
||||
" * Update children and parents\n",
|
||||
"* Set the last node as a terminating node\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(m), where m is the length of the word\n",
|
||||
"* Space: O(h) for the recursion depth (tree height), or O(1) if using an iterative approach\n",
|
||||
"\n",
|
||||
"### remove\n",
|
||||
"\n",
|
||||
"* Determine the matching terminating node by calling the find method\n",
|
||||
"* If the matching node has children, remove the terminator to prevent orphaning its children\n",
|
||||
"* Set the parent node to the matching node's parent\n",
|
||||
"* We'll be looping up the parent chain to propagate the delete\n",
|
||||
"* While the parent is valid\n",
|
||||
" * If the node has children\n",
|
||||
" * Return to prevent orphaning its remaining children\n",
|
||||
" * If the node is a terminating node and it isn't the original matching node from the find call\n",
|
||||
" * Return to prevent deleting this additional valid word\n",
|
||||
" * Remove the parent node's child entry matching the node\n",
|
||||
" * Set the node to the parent\n",
|
||||
" * Set the parent to the parent's parent\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(m+h), where where m is the length of the word and h is the tree height\n",
|
||||
"* Space: O(h) for the recursion depth (tree height), or O(1) if using an iterative approach\n",
|
||||
"\n",
|
||||
"### list_words\n",
|
||||
"\n",
|
||||
"* Do a pre-order traversal, passing down the current word\n",
|
||||
" * When you reach a terminating node, add it to the list of results\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n)\n",
|
||||
"* Space: O(h) for the recursion depth (tree height), or O(1) if using an iterative approach"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting trie.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile trie.py\n",
|
||||
"from collections import OrderedDict\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Node(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, key, parent=None, terminates=False):\n",
|
||||
" self.key = key\n",
|
||||
" self.terminates = False\n",
|
||||
" self.parent = parent\n",
|
||||
" self.children = {}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Trie(object):\n",
|
||||
"\n",
|
||||
" def __init__(self):\n",
|
||||
" self.root = Node('')\n",
|
||||
"\n",
|
||||
" def find(self, word):\n",
|
||||
" if word is None:\n",
|
||||
" raise TypeError('word cannot be None')\n",
|
||||
" node = self.root\n",
|
||||
" for char in word:\n",
|
||||
" if char in node.children:\n",
|
||||
" node = node.children[char]\n",
|
||||
" else:\n",
|
||||
" return None\n",
|
||||
" return node if node.terminates else None\n",
|
||||
"\n",
|
||||
" def insert(self, word):\n",
|
||||
" if word is None:\n",
|
||||
" raise TypeError('word cannot be None')\n",
|
||||
" node = self.root\n",
|
||||
" parent = None\n",
|
||||
" for char in word:\n",
|
||||
" if char in node.children:\n",
|
||||
" node = node.children[char]\n",
|
||||
" else:\n",
|
||||
" node.children[char] = Node(char, parent=node)\n",
|
||||
" node = node.children[char]\n",
|
||||
" node.terminates = True\n",
|
||||
"\n",
|
||||
" def remove(self, word):\n",
|
||||
" if word is None:\n",
|
||||
" raise TypeError('word cannot be None')\n",
|
||||
" node = self.find(word)\n",
|
||||
" if node is None:\n",
|
||||
" raise KeyError('word does not exist')\n",
|
||||
" node.terminates = False\n",
|
||||
" parent = node.parent\n",
|
||||
" while parent is not None:\n",
|
||||
" # As we are propagating the delete up the \n",
|
||||
" # parents, if this node has children, stop\n",
|
||||
" # here to prevent orphaning its children.\n",
|
||||
" # Or\n",
|
||||
" # if this node is a terminating node that is\n",
|
||||
" # not the terminating node of the input word, \n",
|
||||
" # stop to prevent removing the associated word.\n",
|
||||
" if node.children or node.terminates:\n",
|
||||
" return\n",
|
||||
" del parent.children[node.key]\n",
|
||||
" node = parent\n",
|
||||
" parent = parent.parent\n",
|
||||
"\n",
|
||||
" def list_words(self):\n",
|
||||
" result = []\n",
|
||||
" curr_word = ''\n",
|
||||
" self._list_words(self.root, curr_word, result)\n",
|
||||
" return result\n",
|
||||
"\n",
|
||||
" def _list_words(self, node, curr_word, result):\n",
|
||||
" if node is None:\n",
|
||||
" return\n",
|
||||
" for key, child in node.children.items():\n",
|
||||
" if child.terminates:\n",
|
||||
" result.append(curr_word + key)\n",
|
||||
" self._list_words(child, curr_word + key, result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%run trie.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_trie.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_trie.py\n",
|
||||
"from nose.tools import assert_true\n",
|
||||
"from nose.tools import raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestTrie(object): \n",
|
||||
"\n",
|
||||
" def test_trie(self):\n",
|
||||
" trie = Trie()\n",
|
||||
"\n",
|
||||
" print('Test: Insert')\n",
|
||||
" words = ['a', 'at', 'has', 'hat', 'he',\n",
|
||||
" 'me', 'men', 'mens', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" trie.insert(word)\n",
|
||||
" for word in trie.list_words():\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
" \n",
|
||||
" print('Test: Remove me')\n",
|
||||
" trie.remove('me')\n",
|
||||
" words_removed = ['me']\n",
|
||||
" words = ['a', 'at', 'has', 'hat', 'he',\n",
|
||||
" 'men', 'mens', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
" for word in words_removed:\n",
|
||||
" assert_true(trie.find(word) is None)\n",
|
||||
"\n",
|
||||
" print('Test: Remove mens')\n",
|
||||
" trie.remove('mens')\n",
|
||||
" words_removed = ['me', 'mens']\n",
|
||||
" words = ['a', 'at', 'has', 'hat', 'he',\n",
|
||||
" 'men', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
" for word in words_removed:\n",
|
||||
" assert_true(trie.find(word) is None)\n",
|
||||
"\n",
|
||||
" print('Test: Remove a')\n",
|
||||
" trie.remove('a')\n",
|
||||
" words_removed = ['a', 'me', 'mens']\n",
|
||||
" words = ['at', 'has', 'hat', 'he',\n",
|
||||
" 'men', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
" for word in words_removed:\n",
|
||||
" assert_true(trie.find(word) is None)\n",
|
||||
"\n",
|
||||
" print('Test: Remove has')\n",
|
||||
" trie.remove('has')\n",
|
||||
" words_removed = ['a', 'has', 'me', 'mens']\n",
|
||||
" words = ['at', 'hat', 'he',\n",
|
||||
" 'men', 'met']\n",
|
||||
" for word in words:\n",
|
||||
" assert_true(trie.find(word) is not None)\n",
|
||||
" for word in words_removed:\n",
|
||||
" assert_true(trie.find(word) is None)\n",
|
||||
"\n",
|
||||
" print('Success: test_trie')\n",
|
||||
"\n",
|
||||
" @raises(Exception)\n",
|
||||
" def test_trie_remove_invalid(self):\n",
|
||||
" print('Test: Remove from empty trie')\n",
|
||||
" trie = Trie()\n",
|
||||
" assert_true(trie.remove('foo') is None) \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestTrie()\n",
|
||||
" test.test_trie()\n",
|
||||
" test.test_trie_remove_invalid()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Test: Insert\n",
|
||||
"Test: Remove me\n",
|
||||
"Test: Remove mens\n",
|
||||
"Test: Remove a\n",
|
||||
"Test: Remove has\n",
|
||||
"Success: test_trie\n",
|
||||
"Test: Remove from empty trie\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_trie.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
0
math_probability/add_digits/__init__.py
Normal file
0
math_probability/add_digits/__init__.py
Normal file
176
math_probability/add_digits/add_digits_challenge.ipynb
Normal file
176
math_probability/add_digits/add_digits_challenge.ipynb
Normal file
@ -0,0 +1,176 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given an int, repeatedly add its digits until the result is one digit.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume num is not negative?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"* None input -> TypeError\n",
|
||||
"* negative input -> ValueError\n",
|
||||
"* 9 -> 9\n",
|
||||
"* 138 -> 3\n",
|
||||
"* 65536 -> 7\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def add_digits(self, val):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_add_digits.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestAddDigits(object):\n",
|
||||
"\n",
|
||||
" def test_add_digits(self, func):\n",
|
||||
" assert_raises(TypeError, func, None)\n",
|
||||
" assert_raises(ValueError, func, -1)\n",
|
||||
" assert_equal(func(0), 0)\n",
|
||||
" assert_equal(func(9), 9)\n",
|
||||
" assert_equal(func(138), 3)\n",
|
||||
" assert_equal(func(65536), 7) \n",
|
||||
" print('Success: test_add_digits')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestAddDigits()\n",
|
||||
" solution = Solution()\n",
|
||||
" test.test_add_digits(solution.add_digits)\n",
|
||||
" try:\n",
|
||||
" test.test_add_digits(solution.add_digits_optimized)\n",
|
||||
" except NameError:\n",
|
||||
" # Alternate solutions are only defined\n",
|
||||
" # in the solutions file\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
224
math_probability/add_digits/add_digits_solution.ipynb
Normal file
224
math_probability/add_digits/add_digits_solution.ipynb
Normal file
@ -0,0 +1,224 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Given an int, repeatedly add its digits until the result is one digit.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume num is not negative?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"* None input -> TypeError\n",
|
||||
"* negative input -> ValueError\n",
|
||||
"* 9 -> 9\n",
|
||||
"* 138 -> 3\n",
|
||||
"* 65536 -> 7\n",
|
||||
"</pre>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"The naive solution simply isolates each digit with with modulo and integer division. We'll add each isolated digit to a list and sum the values.\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"138 % 10 = 8 -> isolated\n",
|
||||
"138 // 10 = 13\n",
|
||||
"13 % 10 = 3 -> isolated\n",
|
||||
"13 // 10 = 1\n",
|
||||
"1 % 10 = 1 -> isolated\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"A more optimal solution exists, by recognizing this is a digital root. See the [Wikipedia article](https://en.wikipedia.org/wiki/Digital_root) for more information.\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(1)\n",
|
||||
"* Space: O(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def add_digits(self, num):\n",
|
||||
" if num is None:\n",
|
||||
" raise TypeError('num cannot be None')\n",
|
||||
" if num < 0:\n",
|
||||
" raise ValueError('num cannot be negative')\n",
|
||||
" digits = []\n",
|
||||
" while num != 0:\n",
|
||||
" digits.append(num % 10)\n",
|
||||
" num //= 10\n",
|
||||
" digits_sum = sum(digits)\n",
|
||||
" if digits_sum >= 10:\n",
|
||||
" return self.add_digits(digits_sum)\n",
|
||||
" else:\n",
|
||||
" return digits_sum\n",
|
||||
"\n",
|
||||
" def add_digits_optimized(self, num):\n",
|
||||
" if num is None:\n",
|
||||
" raise TypeError('num cannot be None')\n",
|
||||
" if num < 0:\n",
|
||||
" raise ValueError('num cannot be negative')\n",
|
||||
" if num == 0:\n",
|
||||
" return 0\n",
|
||||
" elif num % 9 == 0:\n",
|
||||
" return 9\n",
|
||||
" else:\n",
|
||||
" return num % 9"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_add_digits.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_add_digits.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestAddDigits(object):\n",
|
||||
"\n",
|
||||
" def test_add_digits(self, func):\n",
|
||||
" assert_raises(TypeError, func, None)\n",
|
||||
" assert_raises(ValueError, func, -1)\n",
|
||||
" assert_equal(func(0), 0)\n",
|
||||
" assert_equal(func(9), 9)\n",
|
||||
" assert_equal(func(138), 3)\n",
|
||||
" assert_equal(func(65536), 7) \n",
|
||||
" print('Success: test_add_digits')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestAddDigits()\n",
|
||||
" solution = Solution()\n",
|
||||
" test.test_add_digits(solution.add_digits)\n",
|
||||
" try:\n",
|
||||
" test.test_add_digits(solution.add_digits_optimized)\n",
|
||||
" except NameError:\n",
|
||||
" # Alternate solutions are only defined\n",
|
||||
" # in the solutions file\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_add_digits\n",
|
||||
"Success: test_add_digits\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_add_digits.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.4.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
29
math_probability/add_digits/test_add_digits.py
Normal file
29
math_probability/add_digits/test_add_digits.py
Normal file
@ -0,0 +1,29 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestAddDigits(object):
|
||||
|
||||
def test_add_digits(self, func):
|
||||
assert_raises(TypeError, func, None)
|
||||
assert_raises(ValueError, func, -1)
|
||||
assert_equal(func(0), 0)
|
||||
assert_equal(func(9), 9)
|
||||
assert_equal(func(138), 3)
|
||||
assert_equal(func(65536), 7)
|
||||
print('Success: test_add_digits')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestAddDigits()
|
||||
solution = Solution()
|
||||
test.test_add_digits(solution.add_digits)
|
||||
try:
|
||||
test.test_add_digits(solution.add_digits_optimized)
|
||||
except NameError:
|
||||
# Alternate solutions are only defined
|
||||
# in the solutions file
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
math_probability/generate_primes/__init__.py
Normal file
0
math_probability/generate_primes/__init__.py
Normal file
169
math_probability/generate_primes/check_prime_challenge.ipynb
Normal file
169
math_probability/generate_primes/check_prime_challenge.ipynb
Normal file
@ -0,0 +1,169 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Generate a list of primes.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is it correct that 1 is not considered a prime number?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> Exception\n",
|
||||
"* Not an int -> Exception\n",
|
||||
"* 20 -> 2, 3, 5, 7, 11, 13, 17, 19"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class PrimeGenerator(object):\n",
|
||||
"\n",
|
||||
" def generate_primes(self, max_num):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_generate_primes.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestMath(object):\n",
|
||||
"\n",
|
||||
" def test_generate_primes(self):\n",
|
||||
" prime_generator = PrimeGenerator()\n",
|
||||
" assert_raises(TypeError, prime_generator.generate_primes, None)\n",
|
||||
" assert_raises(TypeError, prime_generator.generate_primes, 98.6)\n",
|
||||
" assert_equal(prime_generator.generate_primes(20), [False, False, True, \n",
|
||||
" True, False, True, \n",
|
||||
" False, True, False, \n",
|
||||
" False, False, True, \n",
|
||||
" False, True, False, \n",
|
||||
" False, False, True, \n",
|
||||
" False, True])\n",
|
||||
" print('Success: generate_primes')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestMath()\n",
|
||||
" test.test_generate_primes()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
220
math_probability/generate_primes/check_prime_solution.ipynb
Normal file
220
math_probability/generate_primes/check_prime_solution.ipynb
Normal file
@ -0,0 +1,220 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Generate a list of primes.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is it correct that 1 is not considered a prime number?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> Exception\n",
|
||||
"* Not an int -> Exception\n",
|
||||
"* 20 -> 2, 3, 5, 7, 11, 13, 17, 19"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"For a number to be prime, it must be 2 or greater and cannot be divisible by another number other than itself (and 1).\n",
|
||||
"\n",
|
||||
"We'll use the Sieve of Eratosthenes. All non-prime numbers are divisible by a prime number.\n",
|
||||
"\n",
|
||||
"* Use an array (or bit array, bit vector) to keep track of each integer up to the max\n",
|
||||
"* Start at 2, end at sqrt(max)\n",
|
||||
" * We can use sqrt(max) instead of max because:\n",
|
||||
" * For each value that divides the input number evenly, there is a complement b where a * b = n\n",
|
||||
" * If a > sqrt(n) then b < sqrt(n) because sqrt(n^2) = n\n",
|
||||
" * \"Cross off\" all numbers divisible by 2, 3, 5, 7, ... by setting array[index] to False\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(n log log n)\n",
|
||||
"* Space: O(n)\n",
|
||||
"\n",
|
||||
"Wikipedia's animation:\n",
|
||||
"\n",
|
||||
"![alt text](https://upload.wikimedia.org/wikipedia/commons/b/b9/Sieve_of_Eratosthenes_animation.gif)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import math\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class PrimeGenerator(object):\n",
|
||||
"\n",
|
||||
" def generate_primes(self, max_num):\n",
|
||||
" if max_num is None:\n",
|
||||
" raise TypeError('max_num cannot be None')\n",
|
||||
" array = [True] * max_num\n",
|
||||
" array[0] = False\n",
|
||||
" array[1] = False\n",
|
||||
" prime = 2\n",
|
||||
" while prime <= math.sqrt(max_num):\n",
|
||||
" self._cross_off(array, prime)\n",
|
||||
" prime = self._next_prime(array, prime)\n",
|
||||
" return array\n",
|
||||
"\n",
|
||||
" def _cross_off(self, array, prime):\n",
|
||||
" for index in range(prime*prime, len(array), prime):\n",
|
||||
" # Start with prime*prime because if we have a k*prime\n",
|
||||
" # where k < prime, this value would have already been\n",
|
||||
" # previously crossed off\n",
|
||||
" array[index] = False\n",
|
||||
"\n",
|
||||
" def _next_prime(self, array, prime):\n",
|
||||
" next = prime + 1\n",
|
||||
" while next < len(array) and not array[next]:\n",
|
||||
" next += 1\n",
|
||||
" return next"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_generate_primes.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_generate_primes.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestMath(object):\n",
|
||||
"\n",
|
||||
" def test_generate_primes(self):\n",
|
||||
" prime_generator = PrimeGenerator()\n",
|
||||
" assert_raises(TypeError, prime_generator.generate_primes, None)\n",
|
||||
" assert_raises(TypeError, prime_generator.generate_primes, 98.6)\n",
|
||||
" assert_equal(prime_generator.generate_primes(20), [False, False, True, \n",
|
||||
" True, False, True, \n",
|
||||
" False, True, False, \n",
|
||||
" False, False, True, \n",
|
||||
" False, True, False, \n",
|
||||
" False, False, True, \n",
|
||||
" False, True])\n",
|
||||
" print('Success: generate_primes')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestMath()\n",
|
||||
" test.test_generate_primes()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: generate_primes\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_generate_primes.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
26
math_probability/generate_primes/test_generate_primes.py
Normal file
26
math_probability/generate_primes/test_generate_primes.py
Normal file
@ -0,0 +1,26 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestMath(object):
|
||||
|
||||
def test_generate_primes(self):
|
||||
prime_generator = PrimeGenerator()
|
||||
assert_raises(TypeError, prime_generator.generate_primes, None)
|
||||
assert_raises(TypeError, prime_generator.generate_primes, 98.6)
|
||||
assert_equal(prime_generator.generate_primes(20), [False, False, True,
|
||||
True, False, True,
|
||||
False, True, False,
|
||||
False, False, True,
|
||||
False, True, False,
|
||||
False, False, True,
|
||||
False, True])
|
||||
print('Success: generate_primes')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestMath()
|
||||
test.test_generate_primes()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
math_probability/math_ops/__init__.py
Normal file
0
math_probability/math_ops/__init__.py
Normal file
190
math_probability/math_ops/math_ops_challenge.ipynb
Normal file
190
math_probability/math_ops/math_ops_challenge.ipynb
Normal file
@ -0,0 +1,190 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Create a class with an insert method to insert an int to a list. It should also support calculating the max, min, mean, and mode in O(1).\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Is there a range of inputs?\n",
|
||||
" * 0 <= item <= 100\n",
|
||||
"* Should mean return a float?\n",
|
||||
" * Yes\n",
|
||||
"* Should the other results return an int?\n",
|
||||
" * Yes\n",
|
||||
"* If there are multiple modes, what do we return?\n",
|
||||
" * Any of the modes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> TypeError\n",
|
||||
"* [] -> ValueError\n",
|
||||
"* [5, 2, 7, 9, 9, 2, 9, 4, 3, 3, 2]\n",
|
||||
" * max: 9\n",
|
||||
" * min: 2\n",
|
||||
" * mean: 55\n",
|
||||
" * mode: 9 or 2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, upper_limit=100):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" def insert(self, val):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_math_ops.py\n",
|
||||
"from nose.tools import assert_equal, assert_true, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestMathOps(object):\n",
|
||||
"\n",
|
||||
" def test_math_ops(self):\n",
|
||||
" solution = Solution()\n",
|
||||
" assert_raises(TypeError, solution.insert, None)\n",
|
||||
" solution.insert(5)\n",
|
||||
" solution.insert(2)\n",
|
||||
" solution.insert(7)\n",
|
||||
" solution.insert(9)\n",
|
||||
" solution.insert(9)\n",
|
||||
" solution.insert(2)\n",
|
||||
" solution.insert(9)\n",
|
||||
" solution.insert(4)\n",
|
||||
" solution.insert(3)\n",
|
||||
" solution.insert(3)\n",
|
||||
" solution.insert(2)\n",
|
||||
" assert_equal(solution.max, 9)\n",
|
||||
" assert_equal(solution.min, 2)\n",
|
||||
" assert_equal(solution.mean, 5)\n",
|
||||
" assert_true(solution.mode in (2, 92))\n",
|
||||
" print('Success: test_math_ops')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestMathOps()\n",
|
||||
" test.test_math_ops()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
236
math_probability/math_ops/math_ops_solution.ipynb
Normal file
236
math_probability/math_ops/math_ops_solution.ipynb
Normal file
@ -0,0 +1,236 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Create a class with an insert method to insert an int to a list. It should also support calculating the max, min, mean, and mode in O(1).\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Is there a range of inputs?\n",
|
||||
" * 0 <= item <= 100\n",
|
||||
"* Should mean return a float?\n",
|
||||
" * Yes\n",
|
||||
"* Should the other results return an int?\n",
|
||||
" * Yes\n",
|
||||
"* If there are multiple modes, what do we return?\n",
|
||||
" * Any of the modes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> TypeError\n",
|
||||
"* [] -> ValueError\n",
|
||||
"* [5, 2, 7, 9, 9, 2, 9, 4, 3, 3, 2]\n",
|
||||
" * max: 9\n",
|
||||
" * min: 2\n",
|
||||
" * mean: 55\n",
|
||||
" * mode: 9 or 2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"* We'll init our max and min to None. Alternatively, we can init them to -sys.maxsize and sys.maxsize, respectively.\n",
|
||||
"* For mean, we'll keep track of the number of items we have inserted so far, as well as the running sum.\n",
|
||||
"* For mode, we'll keep track of the current mode and an array with the size of the given upper limit\n",
|
||||
" * Each element in the array will be init to 0\n",
|
||||
" * Each time we insert, we'll increment the element corresponding to the inserted item's value\n",
|
||||
"* On each insert:\n",
|
||||
" * Update the max and min\n",
|
||||
" * Update the mean by calculating running_sum / num_items\n",
|
||||
" * Update the mode by comparing the mode array's value with the current mode\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(1)\n",
|
||||
"* Space: O(1), we are treating the 101 element array as a constant O(1), we could also see this as O(k)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from __future__ import division\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def __init__(self, upper_limit=100):\n",
|
||||
" self.max = None\n",
|
||||
" self.min = None\n",
|
||||
" # Mean\n",
|
||||
" self.num_items = 0\n",
|
||||
" self.running_sum = 0\n",
|
||||
" self.mean = None\n",
|
||||
" # Mode\n",
|
||||
" self.array = [0] * (upper_limit + 1)\n",
|
||||
" self.mode_ocurrences = 0\n",
|
||||
" self.mode = None\n",
|
||||
"\n",
|
||||
" def insert(self, val):\n",
|
||||
" if val is None:\n",
|
||||
" raise TypeError('val cannot be None')\n",
|
||||
" if self.max is None or val > self.max:\n",
|
||||
" self.max = val\n",
|
||||
" if self.min is None or val < self.min:\n",
|
||||
" self.min = val\n",
|
||||
" # Calculate the mean\n",
|
||||
" self.num_items += 1\n",
|
||||
" self.running_sum += val\n",
|
||||
" self.mean = self.running_sum / self.num_items\n",
|
||||
" # Calculate the mode\n",
|
||||
" self.array[val] += 1\n",
|
||||
" if self.array[val] > self.mode_ocurrences:\n",
|
||||
" self.mode_ocurrences = self.array[val]\n",
|
||||
" self.mode = val"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_math_ops.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_math_ops.py\n",
|
||||
"from nose.tools import assert_equal, assert_true, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestMathOps(object):\n",
|
||||
"\n",
|
||||
" def test_math_ops(self):\n",
|
||||
" solution = Solution()\n",
|
||||
" assert_raises(TypeError, solution.insert, None)\n",
|
||||
" solution.insert(5)\n",
|
||||
" solution.insert(2)\n",
|
||||
" solution.insert(7)\n",
|
||||
" solution.insert(9)\n",
|
||||
" solution.insert(9)\n",
|
||||
" solution.insert(2)\n",
|
||||
" solution.insert(9)\n",
|
||||
" solution.insert(4)\n",
|
||||
" solution.insert(3)\n",
|
||||
" solution.insert(3)\n",
|
||||
" solution.insert(2)\n",
|
||||
" assert_equal(solution.max, 9)\n",
|
||||
" assert_equal(solution.min, 2)\n",
|
||||
" assert_equal(solution.mean, 5)\n",
|
||||
" assert_true(solution.mode in (2, 9))\n",
|
||||
" print('Success: test_math_ops')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestMathOps()\n",
|
||||
" test.test_math_ops()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_math_ops\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_math_ops.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
33
math_probability/math_ops/test_math_ops.py
Normal file
33
math_probability/math_ops/test_math_ops.py
Normal file
@ -0,0 +1,33 @@
|
||||
from nose.tools import assert_equal, assert_true, assert_raises
|
||||
|
||||
|
||||
class TestMathOps(object):
|
||||
|
||||
def test_math_ops(self):
|
||||
solution = Solution()
|
||||
assert_raises(TypeError, solution.insert, None)
|
||||
solution.insert(5)
|
||||
solution.insert(2)
|
||||
solution.insert(7)
|
||||
solution.insert(9)
|
||||
solution.insert(9)
|
||||
solution.insert(2)
|
||||
solution.insert(9)
|
||||
solution.insert(4)
|
||||
solution.insert(3)
|
||||
solution.insert(3)
|
||||
solution.insert(2)
|
||||
assert_equal(solution.max, 9)
|
||||
assert_equal(solution.min, 2)
|
||||
assert_equal(solution.mean, 5)
|
||||
assert_true(solution.mode in (2, 9))
|
||||
print('Success: test_math_ops')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestMathOps()
|
||||
test.test_math_ops()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
math_probability/power_two/__init__.py
Normal file
0
math_probability/power_two/__init__.py
Normal file
171
math_probability/power_two/power_two_challenge.ipynb
Normal file
171
math_probability/power_two/power_two_challenge.ipynb
Normal file
@ -0,0 +1,171 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Challenge Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Determine if a number is a power of two.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)\n",
|
||||
"* [Solution Notebook](#Solution-Notebook)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the input number an int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Is the output a boolean?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> TypeError\n",
|
||||
"* 0 -> False\n",
|
||||
"* 1 -> True\n",
|
||||
"* 2 -> True\n",
|
||||
"* 15 -> False\n",
|
||||
"* 16 -> True"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def is_power_of_two(self, val):\n",
|
||||
" # TODO: Implement me\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**The following unit test is expected to fail until you solve the challenge.**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %load test_is_power_of_two.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestSolution(object):\n",
|
||||
"\n",
|
||||
" def test_is_power_of_two(self):\n",
|
||||
" solution = Solution()\n",
|
||||
" assert_raises(TypeError, solution.is_power_of_two, None)\n",
|
||||
" assert_equal(solution.is_power_of_two(0), False)\n",
|
||||
" assert_equal(solution.is_power_of_two(1), True)\n",
|
||||
" assert_equal(solution.is_power_of_two(2), True)\n",
|
||||
" assert_equal(solution.is_power_of_two(15), False)\n",
|
||||
" assert_equal(solution.is_power_of_two(16), True)\n",
|
||||
" print('Success: test_is_power_of_two')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestSolution()\n",
|
||||
" test.test_is_power_of_two()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Solution Notebook\n",
|
||||
"\n",
|
||||
"Review the [Solution Notebook]() for a discussion on algorithms and code solutions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
206
math_probability/power_two/power_two_solution.ipynb
Normal file
206
math_probability/power_two/power_two_solution.ipynb
Normal file
@ -0,0 +1,206 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Solution Notebook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Problem: Determine if a number is a power of two.\n",
|
||||
"\n",
|
||||
"* [Constraints](#Constraints)\n",
|
||||
"* [Test Cases](#Test-Cases)\n",
|
||||
"* [Algorithm](#Algorithm)\n",
|
||||
"* [Code](#Code)\n",
|
||||
"* [Unit Test](#Unit-Test)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraints\n",
|
||||
"\n",
|
||||
"* Is the input number an int?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume the inputs are valid?\n",
|
||||
" * No\n",
|
||||
"* Is the output a boolean?\n",
|
||||
" * Yes\n",
|
||||
"* Can we assume this fits memory?\n",
|
||||
" * Yes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Test Cases\n",
|
||||
"\n",
|
||||
"* None -> TypeError\n",
|
||||
"* 0 -> False\n",
|
||||
"* 1 -> True\n",
|
||||
"* 2 -> True\n",
|
||||
"* 15 -> False\n",
|
||||
"* 16 -> True"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Algorithm\n",
|
||||
"\n",
|
||||
"We can use bit manipulation to determine if a number is a power of two. \n",
|
||||
"\n",
|
||||
"For a number to be a power of two, there must only be one bit that is a `1`. \n",
|
||||
"\n",
|
||||
"We can use the following bit manipulation trick to determine this:\n",
|
||||
"\n",
|
||||
"`n & (n - 1)`\n",
|
||||
"\n",
|
||||
"Here's an example why:\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"0000 1000 = n\n",
|
||||
"0000 0001 = 1\n",
|
||||
"0000 0111 = n-1\n",
|
||||
"\n",
|
||||
"0000 1000 = n\n",
|
||||
"0000 0111 = n-1\n",
|
||||
"0000 0000 = n & n-1, result = 0\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"Complexity:\n",
|
||||
"* Time: O(1)\n",
|
||||
"* Space: O(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Solution(object):\n",
|
||||
"\n",
|
||||
" def is_power_of_two(self, n):\n",
|
||||
" if n is None:\n",
|
||||
" raise TypeError('n cannot be None')\n",
|
||||
" if n <= 0:\n",
|
||||
" return False\n",
|
||||
" return (n & (n - 1)) == 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unit Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting test_is_power_of_two.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile test_is_power_of_two.py\n",
|
||||
"from nose.tools import assert_equal, assert_raises\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TestSolution(object):\n",
|
||||
"\n",
|
||||
" def test_is_power_of_two(self):\n",
|
||||
" solution = Solution()\n",
|
||||
" assert_raises(TypeError, solution.is_power_of_two, None)\n",
|
||||
" assert_equal(solution.is_power_of_two(0), False)\n",
|
||||
" assert_equal(solution.is_power_of_two(1), True)\n",
|
||||
" assert_equal(solution.is_power_of_two(2), True)\n",
|
||||
" assert_equal(solution.is_power_of_two(15), False)\n",
|
||||
" assert_equal(solution.is_power_of_two(16), True)\n",
|
||||
" print('Success: test_is_power_of_two')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" test = TestSolution()\n",
|
||||
" test.test_is_power_of_two()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Success: test_is_power_of_two\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%run -i test_is_power_of_two.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
23
math_probability/power_two/test_is_power_of_two.py
Normal file
23
math_probability/power_two/test_is_power_of_two.py
Normal file
@ -0,0 +1,23 @@
|
||||
from nose.tools import assert_equal, assert_raises
|
||||
|
||||
|
||||
class TestSolution(object):
|
||||
|
||||
def test_is_power_of_two(self):
|
||||
solution = Solution()
|
||||
assert_raises(TypeError, solution.is_power_of_two, None)
|
||||
assert_equal(solution.is_power_of_two(0), False)
|
||||
assert_equal(solution.is_power_of_two(1), True)
|
||||
assert_equal(solution.is_power_of_two(2), True)
|
||||
assert_equal(solution.is_power_of_two(15), False)
|
||||
assert_equal(solution.is_power_of_two(16), True)
|
||||
print('Success: test_is_power_of_two')
|
||||
|
||||
|
||||
def main():
|
||||
test = TestSolution()
|
||||
test.test_is_power_of_two()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user