diff --git a/04_cohort_three/live_code/4_recursive_ds.ipynb b/04_cohort_three/live_code/4_recursive_ds.ipynb new file mode 100644 index 0000000..f388f59 --- /dev/null +++ b/04_cohort_three/live_code/4_recursive_ds.ipynb @@ -0,0 +1,870 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e606b619-c770-4437-9a7e-b5af87141aaf", + "metadata": {}, + "source": [ + "# Recursive Data Structures\n", + "\n", + "## Outline\n", + "\n", + "- Trees\n", + "\n", + "- Anatomy, tree traversal methods\n", + "\n", + "- Binary Search Trees\n", + "\n", + "- Graphs\n", + "\n", + "- Nearest Neighbor Problem\n", + "\n", + "# Trees\n", + "\n", + "## Introduction to Trees\n", + "\n", + "- Not all data has a natural linear order. Organization charts and\n", + " file storage systems have a *hierarchical structure*, in which each\n", + " entity is linked to multiple entities below it\n", + "\n", + "- This type of data is represented using a *tree*. A tree is either\n", + "\n", + " - Empty\n", + "\n", + " - Has a *root value* connected to any number of other trees,\n", + " called *subtrees*\n", + "\n", + "- We draw the root at the top of the tree\n", + "\n", + "## Anatomy of a Tree\n", + "\n", + "- The *size* of a tree is the number of values in the tree\n", + "\n", + "- A *leaf* is a value with no subtrees. The leaves of this tree are\n", + " labeled E, F, G, J, and I\n", + "\n", + "- The *height* of a tree is the longest path from its root to its\n", + " leaves. The height of this tree is 4\n", + "\n", + "![](./images/tree.png)\n", + "\n", + "## Anatomy of a Tree\n", + "\n", + "- The *children* of a value are all values directly connected\n", + " underneath that value. The children of A are B, C, and D\n", + "\n", + "- The *descendants* of a value are it’s children, the children of its\n", + " children, etc. This can be defined recursively\n", + "\n", + "- The *parent* of a value is the value immediately above and connected\n", + " to it. The parent of H is C\n", + "\n", + "- The *ancestors* of a value are its parent, the parent of its parent,\n", + " etc.\n", + "\n", + "![](./images/tree.png)\n", + "\n", + "## Tree Traversal Methods\n", + "\n", + "- Linear data structures only have one logical way to traverse them.\n", + " Trees can be traversed in different ways\n", + "\n", + "- We’ll look at the following methods of tree traversal and their\n", + " applications\n", + "\n", + " - *Depth First Search* (DFS): Inorder, Preorder, and Postorder\n", + " traversal\n", + "\n", + " - *Breadth First Search* (BFS)\n", + "\n", + "- Note there are other methods not covered\n", + "\n", + "## DFS: Inorder Traversal\n", + "\n", + "1. Traverse the left subtree\n", + "\n", + "2. Visit the root\n", + "\n", + "3. Traverse the right subtree\n", + "\n", + "**Result: 4 2 5 1 6 3**\n", + "\n", + "![](./images/tree_num.png)\n", + "\n", + "## DFS: Inorder Traversal Code\n", + "\n", + "Let’s look at the code to do this" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "4914a874", + "metadata": {}, + "outputs": [], + "source": [ + "class Node:\n", + " \"\"\"Tree class\n", + " \"\"\"\n", + " def __init__(self, key):\n", + " self.left = None\n", + " self.right = None\n", + " self.val = key\n", + " \n", + "def print_inorder(root):\n", + " if root:\n", + " print_inorder(root.left)\n", + " print(root.val, end = \" \")\n", + " print_inorder(root.right)" + ] + }, + { + "cell_type": "markdown", + "id": "abb121a0-9014-4411-8250-bb0fe5a46eee", + "metadata": {}, + "source": [ + "## DFS: Inorder Traversal Code" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "8e4b78cb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4 5 2 6 3 1 " + ] + } + ], + "source": [ + "# node6 = Node(6)\n", + "# node5 = Node(5)\n", + "# node4 = Node(4)\n", + "# node3 = Node(3)\n", + "# node2 = Node(2)\n", + "# node1 = Node(1)\n", + "# node3.left = node6\n", + "# node1.right= node3\n", + "# node2.left = node4\n", + "# node2.right = node5\n", + "# node1.left = node2\n", + "\n", + "root = Node(1)\n", + "root.left = Node(2)\n", + "root.right = Node(3)\n", + "root.left.left = Node(4)\n", + "root.left.right = Node(5)\n", + "root.right.left = Node(6)\n", + "\n", + "\n", + "\n", + "print_inorder(root)" + ] + }, + { + "cell_type": "markdown", + "id": "91306dbf-a4f2-47f3-a88a-1c5da831baae", + "metadata": {}, + "source": [ + "In binary search trees (next section), inorder traversal gives the nodes\n", + "in a non-decreasing order.\n", + "\n", + "## DFS: Inorder Traversal Complexity\n", + "\n", + "Time complexity\n", + "\n", + "- Each node is visited exactly once. The work done at each node is\n", + " constant. $O(n)$\n", + "\n", + "Space complexity\n", + "\n", + "- Dependent on the maximum depth of the recursion, which is the height\n", + " of the tree. $O(h)$\n", + "\n", + "## DFS: Preorder Traversal\n", + "\n", + "1. Visit the root\n", + "\n", + "2. Traverse the left subtree\n", + "\n", + "3. Traverse the right subtree\n", + "\n", + "**Result: 1 2 4 5 3 6**\n", + "\n", + "Preorder traversal is used to create a copy of the tree\n", + "\n", + "![](./images/tree_num.png)\n", + "\n", + "## DFS: Postorder Traversal\n", + "\n", + "1. Traverse the left subtree\n", + "\n", + "2. Traverse the right subtree\n", + "\n", + "3. Visit the root\n", + "\n", + "**Result: 4 5 2 6 3 1**\n", + "\n", + "Postorder traversal is used to delete subtrees. (why?)\n", + "\n", + "![](./images/tree_num.png)\n", + "\n", + "## BFS\n", + "\n", + "BFS (or Level Order Traversal) traverses nodes present in the same level\n", + "before traversing the next level\n", + "\n", + "1. For each node\n", + "\n", + "- The node is visited\n", + "\n", + "- The child nodes are enqueued in a FIFO queue\n", + "\n", + "1. First node is dequeued\n", + "\n", + "2. Child nodes are enqueued\n", + "\n", + "3. Repeat until the queue is empty\n", + "\n", + "**Result: 1 2 3 4 5 6**\n", + "\n", + "![](./images/tree_num.png)\n", + "\n", + "# Binary Search Trees\n", + "\n", + "## BST Definitions\n", + "\n", + "- You can think of a BST as a sorted tree\n", + "\n", + "- A *binary tree* is a tree in which every item has at most two\n", + " subtrees\n", + "\n", + " - The tree used in illustrating DFS and BFS methods is a binary\n", + " tree\n", + "\n", + "- A binary tree is a *binary search tree property* if its value is\n", + " greater than or equal to all items in the left subtree\n", + "\n", + "- A binary tree is a *binary search tree* if every item in the tree\n", + " satisfies the binary search tree property\n", + "\n", + "## BST Efficiency\n", + "\n", + "- Consider the BST on the right. Verify that it is a BST.\n", + "\n", + "- The worst-case run time is $O(h)$, $h$ being the height of the tree\n", + "\n", + " - So the tree on the right is $O(n)$\n", + "\n", + "- A tree of height $h$ can have at most $2^h - 1$ nodes. So we need at\n", + " least log$n$ height to store all of them.\n", + "\n", + " - So if the tree was balanced, then it would be $O(\\text{log}n)$\n", + "\n", + "![](./images/tree_unbal.png)\n", + "\n", + "## BST Efficiency\n", + "\n", + "- Convince yourself that for a balanced BST the search, insert, and\n", + " delete Big-O is all $O(\\text{log}n)$\n", + "\n", + "- Ensuring that a tree is balanced is important\n", + "\n", + " - Red-Black trees (not covered) are trees that balance themselves\n", + "\n", + " - You may also be interested in B-trees, which are used in\n", + " databases\n", + "\n", + "## Live Coding\n", + "\n", + "Given a BST, insert a new node in this BST.\n", + "\n", + "![](./images/insertion.png)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "0fffca91", + "metadata": {}, + "outputs": [], + "source": [ + "# Your code here\n", + "class Node:\n", + " \"\"\"Tree class\n", + " \"\"\"\n", + " def __init__(self, key):\n", + " self.left = None\n", + " self.right = None\n", + " self.val = key\n", + " \n", + "def insert_node(root, value):\n", + " if not root:\n", + " return Node(value)\n", + " if root.val >= value:\n", + " root.left = insert_node(root.left, value)\n", + " return root\n", + " else:\n", + " root.right = insert_node(root.right, value)\n", + " return root" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "181d7b57", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Node at 0x10c5c1d00>" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "root = Node(5)\n", + "insert_node(root, 3)\n", + "insert_node(root, 1)\n", + "insert_node(root, 4)\n", + "insert_node(root, 9)\n", + "insert_node(root, 6)\n", + "insert_node(root, 11)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "8f49c5ba", + "metadata": {}, + "outputs": [], + "source": [ + "node1 = Node(7)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "5ae8443e", + "metadata": {}, + "outputs": [], + "source": [ + "node2 = Node(7)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "7e0f03e5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "node1 == node2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a1040731", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a46d85cc", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "73f2d6ee", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 3 4 5 6 9 11 " + ] + } + ], + "source": [ + "print_inorder(root)" + ] + }, + { + "cell_type": "markdown", + "id": "61fb5b0a", + "metadata": {}, + "source": [ + "\n", + "# Graphs\n", + "\n", + "## Introduction\n", + "\n", + "- We looked at lists and trees, which represent linear and\n", + " hierarchical relationships respectively\n", + "\n", + " - But many relationships are neither\n", + "\n", + " - Friend networks, internet connections, flight connections\n", + "\n", + "- Graphs consist of two parts, *nodes* and *edges*\n", + "\n", + " - A node connected to another is a *neighbor*\n", + "\n", + "![](./images/graph_anat.png)\n", + "\n", + "## Types of Graphs\n", + "\n", + "There are directed and undirected graphs to represent different\n", + "situations\n", + "\n", + "- Friendships: undirected\n", + "\n", + "- Twitter followers: directed\n", + "\n", + "- Who owes who money: directed\n", + "\n", + "- Note that trees are special cases of directed graphs\n", + "\n", + "Graphs can also be weighted, to differentiate strengths between nodes\n", + "\n", + "There are two questions we ask about graphs: Is there a path from node A\n", + "to B? What is the shortest path from node A to B? BFS answers both!\n", + "\n", + "![](./images/graph_weight.png)\n", + "\n", + "## BFS of Graphs\n", + "\n", + "- *Breadth First Search* (BFS) searches graph for a node that meets a\n", + " set of criteria. It starts at the root of the graph and visits all\n", + " nodes at the current depth level before moving on to the nodes at\n", + " the next depth level\n", + "\n", + " - If there are multiple nodes meeting the criteria, then BFS will\n", + " also find the nearest node!\n", + "\n", + "- The issue is that graphs contain *cycles*, so we may visit the same\n", + " node more than once\n", + "\n", + " - Let’s split edges into visited and not visited\n", + "\n", + "- We use a list to keep track of visited nodes\n", + "\n", + "- All the adjacent unvisited nodes of the current level are pushed\n", + " into the queue and the nodes of the current level are marked visited\n", + " and popped from the queue\n", + "\n", + "- Is BFS a recursive or iterative graph search method?\n", + "\n", + "## BFS Example\n", + "\n", + "- Let’s traverse a graph with BFS starting at node “1”\n", + "\n", + "- Visited list and queue start as empty\n", + "\n", + "Visited: \\[ , , , , \\]\n", + "\n", + "Queue: \\[ , , , , \\]\n", + "\n", + "![](./images/graph_bfs.png)\n", + "\n", + "## BFS Example\n", + "\n", + "- We’re at node 1, so we push it onto the visited list and push it\n", + " onto the queue\n", + "\n", + "Visited: \\[1, , , , \\]\n", + "\n", + "Queue: \\[1, , , , \\]\n", + "\n", + "![](./images/graph_bfs.png)\n", + "\n", + "## BFS Example\n", + "\n", + "- Now we visited 1, so it is dequeued.\n", + "\n", + "- At the first level away from node 1, there is 3 and 6.\n", + "\n", + "- We visit 3 and 6, but we have not visited any of it’s neighbors\n", + " (other than 1), so 3 and 6 are enqueued.\n", + "\n", + "Visited: \\[1, 3, 6, , \\]\n", + "\n", + "Queue: \\[3, 6, , , \\]\n", + "\n", + "![](./images/graph_bfs.png)\n", + "\n", + "## BFS Example\n", + "\n", + "- Visit the neighbors of node 3, so we dequeue it\n", + "\n", + "- But we need to enqueue 10, because we haven’t visited its neighbors\n", + "\n", + "Visited: \\[1, 3, 6, 10, \\]\n", + "\n", + "Queue: \\[6, 10, , \\]\n", + "\n", + "![](./images/graph_bfs.png)\n", + "\n", + "## BFS Example\n", + "\n", + "- Visit the neighbors of node 6, which is just 7, so we dequeue it\n", + "\n", + "- But we need to enqueue 7\n", + "\n", + "Visited: \\[1, 3, 6, 10, 7\\]\n", + "\n", + "Queue: \\[10, 7, , \\]\n", + "\n", + "![](./images/graph_bfs.png)\n", + "\n", + "## BFS Example\n", + "\n", + "- Visit the neighbors of node 10, and dequeue 10\n", + "\n", + "- But we already visited those nodes, so the visited list does not\n", + " change\n", + "\n", + "Visited: \\[1, 3, 6, 10, 7\\]\n", + "\n", + "Queue: \\[7, , , , \\]\n", + "\n", + "![](./images/graph_bfs.png)\n", + "\n", + "## BFS Example\n", + "\n", + "- Visit neighbors of 7, which are also all visited\n", + "\n", + "- The queue is empty, so the algorithm ends\n", + "\n", + "Visited: \\[1, 3, 6, 10, 7\\]\n", + "\n", + "Queue: \\[ , , , , \\]\n", + "\n", + "![](./images/graph_bfs.png)\n", + "\n", + "## Time and Space Complexity of BFS\n", + "\n", + "- Each edge and each node must be visited once, so the time complexity\n", + " is $O(n + e)$\n", + "\n", + "- Since we need to store each node of the graph by the end of the\n", + " algorithm, the space complexity is $O(n)$\n", + "\n", + "## Implementing Graphs and BFS\n", + "\n", + "We can represent graphs using the *adjacency list* representation\n", + "\n", + "- Other options include adjacency matrix or using a Python library" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "23428e44", + "metadata": {}, + "outputs": [], + "source": [ + "from collections import deque\n", + "\n", + "class Graph:\n", + " def __init__(self):\n", + " self.graph = {}\n", + "\n", + " def add_edge(self, vertex, neighbors):\n", + " self.graph[vertex] = neighbors" + ] + }, + { + "cell_type": "markdown", + "id": "9f393b7b-3af9-4a07-861c-9e14bc7bea47", + "metadata": {}, + "source": [ + "## Implementing Graphs and BFS" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "32ada213", + "metadata": {}, + "outputs": [], + "source": [ + "def bfs(graph, start):\n", + " visited = set()\n", + " queue = deque([start])\n", + "\n", + " while queue:\n", + " current_vertex = queue.popleft()\n", + "\n", + " if current_vertex not in visited:\n", + " # Process the current vertex\n", + " print(current_vertex, end=' ')\n", + " visited.add(current_vertex)\n", + "\n", + " # Enqueue unvisited neighbors\n", + " for neighbor in graph.graph.get(current_vertex, []):\n", + " if neighbor not in visited:\n", + " queue.append(neighbor)" + ] + }, + { + "cell_type": "markdown", + "id": "3965d53d-8ca1-4372-8e0b-35a2a1486159", + "metadata": {}, + "source": [ + "## Implementing Graphs and BFS" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "3b8d278a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 3 6 10 7 " + ] + } + ], + "source": [ + "# Represent graph from above\n", + "ex_graph = Graph()\n", + "ex_graph.add_edge(1, [3, 6])\n", + "ex_graph.add_edge(3, [10, 6])\n", + "ex_graph.add_edge(6, [3, 7])\n", + "ex_graph.add_edge(10, [3, 7])\n", + "ex_graph.add_edge(7, [10, 6])\n", + "\n", + "# Perform BFS starting from vertex 1\n", + "bfs(ex_graph, 1)" + ] + }, + { + "cell_type": "markdown", + "id": "909bfd55-42c3-4c3c-8279-6489791e4f51", + "metadata": {}, + "source": [ + "## Recursive Graph Search: Preorder Traversal\n", + "\n", + "- Using the same `Graph` class, let’s implement preorder traversal" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d883118d", + "metadata": {}, + "outputs": [], + "source": [ + "def recursive_preorder_traversal(graph, start, visited=None):\n", + " if visited is None:\n", + " visited = set()\n", + "\n", + " # Process the current vertex\n", + " print(start, end=' ')\n", + " visited.add(start)\n", + "\n", + " # Recursive traversal of neighbors\n", + " for neighbor in graph.graph.get(start, []):\n", + " if neighbor not in visited:\n", + " recursive_preorder_traversal(graph, neighbor, visited)" + ] + }, + { + "cell_type": "markdown", + "id": "60bf08d2-4747-41c3-b128-ff00d1bc771d", + "metadata": {}, + "source": [ + "## Recursive Graph Search: Preorder Traversal" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "c4b48ff8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 3 6 10 7 " + ] + } + ], + "source": [ + "bfs(ex_graph, 1)" + ] + }, + { + "cell_type": "markdown", + "id": "c3b6c651-0046-4740-babf-41a312cf51bc", + "metadata": {}, + "source": [ + "# Nearest Neighour Problem\n", + "\n", + "## Nearest Neighbour Problem\n", + "\n", + "- As you may have encountered already, machine learning and\n", + " statistical methods often depend on finding the nearest neighbor to\n", + " a data point\n", + "\n", + " - K-nearest neighbors regression, propensity score matching\n", + "\n", + "- In a $k$ dimensional space, if we conduct a linear search for\n", + " points, the running time will be $O(kn)$ for $n$ data points.\n", + "\n", + "- Can we do better?\n", + "\n", + "## k-d Trees\n", + "\n", + "- k-d trees is short for k dimensional tree (notation is a bit\n", + " unfortunate, different K than KNN)\n", + "\n", + " - It is useful for multidimensional searches\n", + "\n", + "- Let’s discuss the properties of k-d trees and why they work\n", + "\n", + "- Binary tree where each node represents an axis-aligned\n", + " hyperrectangle in the k-dimensional space\n", + "\n", + " - hyperrectangle: rectangle in higher dimensions\n", + "\n", + "- Nodes in the left subtree have coordinates less than the splitting\n", + " dimension of the current node, while nodes in the right subtree have\n", + " coordinates greater than the splitting dimension.\n", + "\n", + "- At each level of the tree, a specific dimension is chosen to split\n", + " the data. The choice of dimension alternates as we traverse down the\n", + " tree.\n", + "\n", + "- Each leaf represents a single point in the k-dimensional space\n", + "\n", + "## k-d Trees Animation\n", + "\n", + "\n", + "\n", + "## Applications and Issues\n", + "\n", + "- Notice k-d trees can also find values within a certain range very\n", + " quickly, not just a specific point\n", + "\n", + "- GIS (geographic information systems) queries\n", + "\n", + "- KNN algorithm\n", + "\n", + "- Computer graphics, such as ray tracing to facilitate efficient space\n", + " partitioning\n", + "\n", + "- Issues occur in high-dimensional spaces and trees can become\n", + " imbalanced\n", + "\n", + "# Recommended Problems and References\n", + "\n", + "## Recommended Readings\n", + "\n", + "- Bhargava: Chapter 6\n", + "\n", + "- Bhargava: Chapter 11, pages 203 to 206 about Trees\n", + "\n", + "## Recommended Problems\n", + "\n", + "- Cormen: Chapter 10 exercises\n", + "\n", + " - 10.3-1, 10.3-2, 10.3-3\n", + "\n", + "- Bhargava: Chapter 6 exercises\n", + "\n", + " - 6.1 to 6.5\n", + "\n", + "## Recommended Problems\n", + "\n", + "- Implement preorder, postorder, and level order traversal. Determine\n", + " the time and space complexity in each case\n", + "\n", + "- Implement a function that find an element in a BST and deletes it.\n", + " The descendants of the deleted node are given to the deleted node’s\n", + " parent.\n", + "\n", + "- Using the `graph` class from the slides, implement BST search such\n", + " that it stops and tell you the distance the node is from the\n", + " starting point.\n", + "\n", + " - For instance, if we searched for 7 in the graph given in the\n", + " slides, it would return `\"Found! Distance 2\"`.\n", + "\n", + " - If we searched for 100 in the graph, it would return\n", + " `\"Not found!\"`\n", + "\n", + "- Implement postorder graph traversal using the `graph` class from the\n", + " slides.\n", + "\n", + "- Implement a function using recursion to find the sum heterogeneous\n", + " nested lists such as \\[\\[1, \\[2\\]\\], \\[\\[\\[3\\]\\]\\], 4, \\[\\[5, 6\\],\n", + " \\[\\[\\[7\\]\\]\\]\\]\\].\n", + "\n", + "## References\n", + "\n", + "- Bhargava, A. Y. (2016). *Grokking algorithms: An illustrated guide\n", + " for programmers and other curious people.* Manning. Chapter 6, 10,\n", + " 11.\n", + "\n", + "- Cormen, T. H. (Ed.). (2009). *Introduction to algorithms* (3rd ed).\n", + " MIT Press. Chapter 12 and 20.\n", + "\n", + "- Horton, D., & Liu, D. (2023, November 19). *CSC148 Lecture Notes*.\n", + " https://www.teach.cs.toronto.edu/~csc148h/winter/notes/" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/04_cohort_three/live_code/Lecture_3_Review.ipynb b/04_cohort_three/live_code/Lecture_3_Review.ipynb new file mode 100644 index 0000000..20faa42 --- /dev/null +++ b/04_cohort_three/live_code/Lecture_3_Review.ipynb @@ -0,0 +1,338 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "f526d35b", + "metadata": {}, + "outputs": [], + "source": [ + "#Recursive function review" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "497c9492", + "metadata": {}, + "outputs": [], + "source": [ + "# Reverse a string\n", + "# reverse_string(\"hello\") -> \"olleh\"\n", + "def reverse_string(s):\n", + " if len(s) <= 1:\n", + " return s\n", + " else:\n", + " return reverse_string(s[1:]) + s[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "0859612c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'olleh'" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse_string(\"hello\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "3c3a7dbc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'h'" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse_string(\"h\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "56615fc3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "''" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse_string(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "d3c0bc58", + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate the power of number using recursion\n", + "# pre-condition: exponent needs to be an integer\n", + "def power(base, exponent):\n", + " if exponent == 0:\n", + " return 1\n", + " elif exponent == 1:\n", + " return base\n", + " else:\n", + " return base * power(base, exponent-1)\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "7b34a403", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1024" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "power(2, 10)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "48d54b03", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "65536" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "power(4, 8)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f1273c3b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n", + "0\n", + "1\n", + "5\n" + ] + } + ], + "source": [ + "# Count occurances in a list\n", + "# return if value is inside list (using recursion, and not using \"in\")\n", + "# Returns True/False\n", + "def is_value_inside_list(lst, value):\n", + " if len(lst) == 0:\n", + " return False\n", + " elif lst[0] == value:\n", + " return True\n", + " else:\n", + " return is_value_inside_list(lst[1:], value)\n", + " \n", + "print(is_value_inside_list([1, 2, 3, 4], 5))\n", + "print(is_value_inside_list([1, 2, 3, 4], 3))\n", + "\n", + "def count_value_inside_lst(lst, value):\n", + " if len(lst) == 0:\n", + " return 0\n", + " else:\n", + " if lst[0] == value:\n", + " return 1 + count_value_inside_lst(lst[1:], value)\n", + " else:\n", + " return count_value_inside_lst(lst[1:], value)\n", + " \n", + "print(count_value_inside_lst([1, 2, 3, 4], 5))\n", + "print(count_value_inside_lst([1, 2, 3, 4], 3))\n", + "print(count_value_inside_lst([1, 2, 2, 2, 3, 2, 4, 2], 2))" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "3b780616", + "metadata": {}, + "outputs": [], + "source": [ + "# check if string is palidrome (the string is the same forwards and backwards) (True/False)\n", + "# racecar\n", + "def is_palindrome(s):\n", + " if len(s) <= 1:\n", + " return True\n", + "# elif len(s) == 1:\n", + "# return True\n", + " else:\n", + " if s[0] == s[-1]:\n", + " return is_palindrome(s[1:-1])\n", + " else:\n", + " return False" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "22572c1b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "is_palindrome(\"racecar\")" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "166971ff", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "is_palindrome(\"racecara\")" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "8e5f2743", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "is_palindrome(\"g\")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "4808a6d5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "is_palindrome(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df8748b2", + "metadata": {}, + "outputs": [], + "source": [ + "# All these functions will have a time complexity of O(n)\n", + "# All these functions will have a space complexity of O(n)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}