Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 184 additions & 42 deletions 02_activities/assignments/assignment_1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,25 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 90,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2\n"
]
}
],
"source": [
"import hashlib\n",
"\n",
"def hash_to_range(input_string: str) -> int:\n",
" hash_object = hashlib.sha256(input_string.encode())\n",
" hash_int = int(hash_object.hexdigest(), 16)\n",
" return (hash_int % 3) + 1\n",
"input_string = \"your_first_name_here\"\n",
"input_string = \"nipun\"\n",
"result = hash_to_range(input_string)\n",
"print(result)\n"
]
Expand Down Expand Up @@ -80,9 +88,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 91,
"metadata": {},
"outputs": [],
"outputs": [
{
"ename": "IndentationError",
"evalue": "expected an indented block (2850872121.py, line 8)",
"output_type": "error",
"traceback": [
"\u001b[0;36m Cell \u001b[0;32mIn[91], line 8\u001b[0;36m\u001b[0m\n\u001b[0;31m # TODO\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mIndentationError\u001b[0m\u001b[0;31m:\u001b[0m expected an indented block\n"
]
}
],
"source": [
"# Definition for a binary tree node.\n",
"# class TreeNode(object):\n",
Expand Down Expand Up @@ -130,18 +147,17 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 106,
"metadata": {},
"outputs": [],
"source": [
"# Step 1\n",
"# Definition for a binary tree node.\n",
"# class TreeNode(object):\n",
"# def __init__(self, val = 0, left = None, right = None):\n",
"# self.val = val\n",
"# self.left = left\n",
"# self.right = right\n",
"def bt_path(root: TreeNode) -> List[List[int]]:\n",
" # TODO"
"class TreeNode(object):\n",
" def __init__(self, val = 0, left = None, right = None):\n",
" self.val = val\n",
" self.left = left\n",
" self.right = right"
]
},
{
Expand Down Expand Up @@ -201,12 +217,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"# Your answer here"
"Given a binary tree, the task is to find all the possible paths from the top (root node) to the botton (left) of the tree."
]
},
{
Expand All @@ -217,12 +235,23 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"# Your answer here"
"#Tree # 1 ->\n",
"[1, 2, 3 , 4 , 5, 6 , 7]\n",
"#Should return\n",
"[('1', '2', '4'), ('1', '2', '5'), ('1', '3', '6'), ('1', '3', '7')]\n",
"\n",
"# Tree # 2\n",
"# the data type in different nodes can be different too\n",
"[1, 2, 3, 3, 5 , 'my_Leaf']\n",
"#hould return\n",
"[('1', '2', '3'), ('1', '2', '5'), ('1', '3', 'my_Leaf')]"
]
},
{
Expand All @@ -235,11 +264,86 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 93,
"metadata": {},
"outputs": [],
"source": [
"# Your answer here"
"# Step 2\n",
"# As per the instructions, the input is a list. I have to first convert the list to a tree\n",
"\n",
"from collections import deque\n",
"from typing import List, Optional\n",
"\n",
"\n",
"def list_to_tree(lst: list[Optional[int]]) -> Optional[TreeNode]:\n",
" if not lst or lst[0] is None:\n",
" return None # Empty tree case\n",
"\n",
" root = TreeNode(lst[0]) # Create the root\n",
" queue = deque([root]) # Queue for level-order insertion\n",
" i = 1 # Index in the list\n",
"\n",
" while i < len(lst):\n",
" node = queue.popleft() # Get the current parent node\n",
"\n",
" # Assign left child\n",
" if i < len(lst) and lst[i] is not None:\n",
" node.left = TreeNode(lst[i])\n",
" queue.append(node.left)\n",
" i += 1\n",
"\n",
" # Assign right child\n",
" if i < len(lst) and lst[i] is not None:\n",
" node.right = TreeNode(lst[i])\n",
" queue.append(node.right)\n",
" i += 1\n",
"\n",
" return root # Return the tree root"
]
},
{
"cell_type": "code",
"execution_count": 95,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[('1', '2', '3'), ('1', '2', '5'), ('1', '2', '6'), ('1', '2', '7')]\n"
]
}
],
"source": [
"# Step 3: Recursive method for Depth first search \n",
"def bt_path(root: TreeNode) -> list[list[int]]:\n",
" # TODO\n",
" def dfs(node, path, result): #base case\n",
" if not node: \n",
" return\n",
" path.append(str(node.val)) # Append current node value to path\n",
" if not node.left and not node.right: # If it's a leaf, add path to result, node.left and node.right will both return false for a leaf node\n",
" #result.append(\"->\".join(path)) #End search\n",
" #print(tuple(path))\n",
" result.append(tuple(path))\n",
" else:\n",
" dfs(node.left, path[:], result) # Recursion for left subtree\n",
" dfs(node.right, path[:], result) # Recursion for right subtree\n",
" path.pop() # Backtrack\n",
"\n",
" result = []\n",
" dfs(root, [], result)\n",
" return result\n",
"\n",
"# Step 1: Convert list to binary tree\n",
"tree_list = [1, 2, 2, 3, 5, 6, 7] # Example from above\n",
"root = list_to_tree(tree_list)\n",
"\n",
"# Step 2: Run DFS to get all root-to-leaf paths\n",
"paths = bt_path(root)\n",
"\n",
"# Step 3: Print result\n",
"print(paths) # Expected Output: ['1->2->5', '1->3']"
]
},
{
Expand All @@ -251,12 +355,24 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"# Your answer here"
"# Your answer here\n",
"\n",
"It can be broken down into a recursive method, because a big tree is made up a smaller trees. A binary free is made up of 2 smaller trees.\n",
"\n",
"\n",
"1. Start at the root → Add the current node’s value to the path list and move down the tree.\n",
"2. Recursively explore left and right children → Call DFS on the left child first, then the right child. \n",
" 2.1 For each node, I store the path taken into a list - 'path'\n",
"3. If a leaf node is reached (no left or right child) → Convert path to a tuple (so that it is immutable now, and can-not be changed) and append it in the list - result\n",
"4. Backtrack → Remove the last node from path (pop()) and try a different path.\n",
"5. Continue until all nodes are visited (if not node, base case) → Once all paths are collected, return the final result list."
]
},
{
Expand All @@ -268,12 +384,19 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"# Your answer here"
"# Your answer here\n",
"\n",
"Time: O(N) Because each path is traversed only once\n",
"Space: O(LogN) for each path, because that is the depth of the tree\n",
" There are N/2 leaves, so N possible paths\n",
" O(NLog(N))"
]
},
{
Expand All @@ -285,12 +408,31 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"# Your answer here"
"# Your answer here\n",
"\n",
"Instead of using a recursive method, I can also use stack data structures\n",
"\n",
"First explaination of how a stack data strucutre would work. A stack is a data structure that works like a stack of plates:\n",
"\n",
"1. You add items to the top (push). (Implement by adding a new element to the left hand side of the list, do-not use append. Use insert(0 , 'value'))\n",
"2. You remove items from the top (pop). - LIFO. (Use pop to remove the right most element)\n",
"3. The last item added is the first one removed (Last In, First Out → LIFO)\n",
"\n",
"This is how we can implement DFS using stacks\n",
"\n",
"1. Start with the root and put it in the stack. (This the root node on the top of the tree)\n",
"2. Take a node from the stack, check if it’s a leaf (has no children).\n",
" - If it’s a leaf, save its path.\n",
" - If not, add its children to the stack (right child first, then left). -> This way the childs are also added to the 'list' of things to check\n",
"3. Repeat until we’ve visited all nodes.\n",
"4. Since we use a stack, we process the left side first (because stacks work in Last In, First Out order)."
]
},
{
Expand Down Expand Up @@ -338,7 +480,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "dsi_participant",
"language": "python",
"name": "python3"
},
Expand All @@ -352,7 +494,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.7"
"version": "3.9.18"
}
},
"nbformat": 4,
Expand Down