diff --git a/labs/03-stacks-queues-exercises.ipynb b/labs/03-stacks-queues-exercises.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..80f776475f0b357cab614c0ae538dd5ebc84b60e --- /dev/null +++ b/labs/03-stacks-queues-exercises.ipynb @@ -0,0 +1,638 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5ce21950", + "metadata": {}, + "source": [ + "NAME:" + ] + }, + { + "cell_type": "markdown", + "id": "2f1f2dcd-96a9-45ef-90a6-4ad488635679", + "metadata": {}, + "source": [ + "# UE5 Fundamentals of Algorithms\n", + "# Lab 3: Stacks and Queues" + ] + }, + { + "cell_type": "markdown", + "id": "b9bd540c-dd15-49ac-bfbd-f2e758688a85", + "metadata": { + "tags": [] + }, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "a18516d6-24ae-4e5c-afb7-43a4435ea868", + "metadata": {}, + "source": [ + "<details style=\"border: 1px\">\n", + "<summary> How to use those notebooks</summary>\n", + " \n", + "For each of the following questions:\n", + "- In the `# YOUR CODE HERE` cell, remove `raise NotImplementedError()` to write your code\n", + "- Write an example of use of your code or make sure the given examples and tests pass\n", + "- Add extra tests in the `#Tests` cell\n", + " \n", + "</details>" + ] + }, + { + "cell_type": "markdown", + "id": "7fdd7e6b-da89-4100-8241-0b0d47caa3ed", + "metadata": { + "tags": [] + }, + "source": [ + "Course reminders:\n", + "\n", + "<img src=\"./figures/stacks-queues.png\" style=\"width:500px\">\n", + "\n", + "- `stacks` follow the Last-In, First-Out (LIFO) principle\n", + "- `queues`follows the First-In, First-Out (FIFO) principle\n", + "\n", + "They have the following operations:\n", + "\n", + "- `empty()`: Checks for emptiness.\n", + "- `full()`: Checks if it's full (if a maximum size was provided during creation).\n", + "- `get()`: Returns (and removes) an element.\n", + "- `push(element)`: Adds an element.\n", + "- `size()`: Returns the size of the list.\n", + "- `peek()`: Returns an element (without removing it).\n", + "- `clear()`: Empties the list.\n", + "- `contains(element)`: Checks if a specified element has been added.\n", + "- `index(element)`: Finds the index of a specified element.\n", + "- `remove(element)`: Removes a specific element (if present)." + ] + }, + { + "cell_type": "markdown", + "id": "d389441b-f86b-41c6-b7ec-6dd89eb61af6", + "metadata": {}, + "source": [ + "## Exercise 1: Implement a Stack\n", + "\n", + "Use the `Stack` object below and implement the above operations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "146beb1c-fcfa-43cb-9718-7bb61e6201bc", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "939f55cb3995a17f3d2e2bd36dfb8a69", + "grade": false, + "grade_id": "cell-bbf71a239f64c912", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "class Stack:\n", + " def __init__(self, max_size=1000):\n", + " # YOUR CODE HERE\n", + " raise NotImplementedError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5afc8b1f-2708-4289-8d54-c6bdada4d184", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Example of use\n", + "s = Stack()\n", + "s.push(10)\n", + "s.push(20)\n", + "s.get() == 20\n", + "s.get() == 10" + ] + }, + { + "cell_type": "markdown", + "id": "6f37285b-a4e6-4261-9c10-3e98f4ef1f08", + "metadata": {}, + "source": [ + "Compare with the `queue` [package](https://docs.python.org/3/library/queue.html) from Python \n", + "\n", + "```python\n", + "import queue\n", + "q1 = queue.Queue()\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7ff762d-e812-433b-8f57-56004477278f", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "b5e41fbfe688c00057177e3c4fb9be19", + "grade": false, + "grade_id": "cell-60ff2cf650eb21cb", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "import queue\n", + "# Tests\n", + "# YOUR CODE HERE\n", + "raise NotImplementedError()" + ] + }, + { + "cell_type": "markdown", + "id": "03a0653e-65c2-4e79-9e83-31765cf19098", + "metadata": {}, + "source": [ + "## Exercise 2: Reverse a string\n", + "\n", + "Use the `Stack` data structure to reverse a string `s` given as input." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b77ae34-ef7c-4664-94e0-8928156f2224", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "128a37273e0e5da052abe4bf08bb1c27", + "grade": false, + "grade_id": "cell-5b0828e97507162e", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def reverse_string(s):\n", + " # YOUR CODE HERE\n", + " raise NotImplementedError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63719c8e-f60c-4544-8e41-cb6380ae4bcf", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Example of use\n", + "reverse_string(\"Hello\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81e93620-0664-4a9d-ba5f-894937c9769e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Tests\n", + "assert reverse_string(\"Hello\") == \"Hello\"[::-1]\n", + "assert reverse_string(\"Hello\") == \"\".join(reversed(\"Hello\"))" + ] + }, + { + "cell_type": "markdown", + "id": "81df9b1e-cfe5-4b69-96a5-c8065259cc7d", + "metadata": {}, + "source": [ + "## Exercise 3: Check if a word is a palindrom\n", + "\n", + "Use the `Stack` to check if a sequence of characters reads the same forward and backward." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf6fbdd5-53c5-45c2-a0c5-a5ed845c4f81", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "048d788477e620bf78240329c0dd8771", + "grade": false, + "grade_id": "is_palindrome", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def is_palindrome(s):\n", + " # YOUR CODE HERE\n", + " raise NotImplementedError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1e3d451-9ac1-4551-9cd5-c3024133495c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Example of use\n", + "is_palindrome(\"ABA\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "586bafba-2fbb-4833-b2e3-609db9b28fbf", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Tests\n", + "assert is_palindrome(\"ABA\")\n", + "assert not is_palindrome(\"ABAB\")" + ] + }, + { + "cell_type": "markdown", + "id": "7a6c95d6-266e-4742-bfef-8b1f2dda4164", + "metadata": {}, + "source": [ + "## Exercise 4: Store unique elements only\n", + "\n", + "Use the `Stack` to create a new class that inherits it and call it `StackUnique` to only store unique values (ie if a value has already been added do not add it)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cab518b1-4d59-45d2-9e69-ae95458eeac5", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "de529eccd1a465d7b9cc2313e5ee5b87", + "grade": false, + "grade_id": "cell-0c6214437a6048f9", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "class StackUnique(Stack):\n", + " # YOUR CODE HERE\n", + " raise NotImplementedError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53ac7eb2-295e-469b-b63b-ffbe876ff620", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Usage example\n", + "s = StackUnique()\n", + "s.push(1)\n", + "s.push(1)\n", + "s.get()\n", + "s.get() if not s.empty() else print(\"no more value\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12847b9d-947f-4181-84cc-d2726199269b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Tests\n", + "s = StackUnique()\n", + "s.push(1)\n", + "s.push(1)\n", + "assert s.get() == 1\n", + "assert s.empty()" + ] + }, + { + "cell_type": "markdown", + "id": "882884c2-1918-4224-9124-81bc55e43d4e", + "metadata": { + "tags": [] + }, + "source": [ + "## Exercise 5: Check if correct number and order of brackets \n", + "\n", + "To verify if a string contains balanced brackets in the correct order, we can use a `Stack` to check if each opening bracket has a matching closing bracket and that they are correctly nested." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "804ea32d-5bf8-42b9-ae52-6318b26f4065", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "816be0322bf46bb7d09b3b8384a5e383", + "grade": false, + "grade_id": "cell-4b9a5ecdee87514e", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def is_balanced(s):\n", + " # YOUR CODE HERE\n", + " raise NotImplementedError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7c86615-db59-4cff-aa16-32c3928fbbae", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Usage example\n", + "is_balanced(\"([])\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aab38745-f306-4015-bcff-563f3c1b4166", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Tests\n", + "assert is_balanced(\"([])\")\n", + "assert is_balanced(\"([{}])\")\n", + "assert not is_balanced(\"(]\")\n", + "assert is_balanced(\"(([]){})\")\n", + "assert not is_balanced(\"({[})\")" + ] + }, + { + "cell_type": "markdown", + "id": "91792d87-9c2b-4a4f-ad6e-1980bb76b06e", + "metadata": {}, + "source": [ + "## Exercice 6: Merge overlapping intervals\n", + "\n", + "Given a list of intervals, where each interval is represented as a list `[start, end]`, your task is to merge all overlapping intervals. Overlapping intervals should be merged into one interval with the start as the minimum of both intervals starts and the end as the maximum of both intervals ends. For example, with input `[[1, 3], [2, 6], [8, 10], [15, 18], [17, 20]]` you may return as output `[[1, 6], [8, 10], [15, 20]]` where 2 pairs intervals have been marged. Here is a way to solve this problem:\n", + "\n", + "\n", + "1. Check if the input list of intervals is empty (if it is, return an empty list)\n", + "2. Sort the intervals by their starting times.\n", + "3. Create an empty stack that will contain the merged intervals.\n", + "4. Iterate through each interval:\n", + " - If the stack is empty or the current interval does not overlap with the last interval in the stack, push the current interval onto the stack.\n", + " - If there is an overlap, pop the last interval from the stack, merge it with the current interval, and push the merged interval back onto the stack.\n", + "5. Convert the stack to a list and return the merged intervals." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a81eb460-4622-44cd-81b9-c89be4bb5b48", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "1ff269074892a79c41fe9a350bac0dee", + "grade": false, + "grade_id": "cell-1a6e476af258654c", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def merge_intervals(intervals):\n", + " # YOUR CODE HERE\n", + " raise NotImplementedError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b02e24d-d498-40f3-a0f9-d6e0e8ad0d2e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Usage example\n", + "intervals = [[1, 3], [2, 6], [8, 10], [15, 18], [17, 20]]\n", + "merged = merge_intervals(intervals)\n", + "print(\"Merged Intervals:\", merged)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c04dfd85-04c7-43e5-8aa5-b4774e253bf4", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Tests\n", + "assert merge_intervals([[1, 3], [2, 6], [8, 10], [15, 18], [17, 20]]) == [[1, 6], [8, 10], [15, 20]]\n", + "assert merge_intervals([[1, 2]]) == [[1, 2]]" + ] + }, + { + "cell_type": "markdown", + "id": "a445d290-b04f-49b5-a8e7-2c6e259daf58", + "metadata": { + "tags": [] + }, + "source": [ + "## Exercise 7 (BONUS): Evaluate a postfix expression\n", + "\n", + "Write a code that given the following expression, provides the following evaluation (using arthmetic operations over numerical values).\n", + "\n", + "Expression: `\"3 4 +\"`\n", + "Evaluation: `3 + 4 = 7`\n", + "\n", + "First step: write a function `apply_operator` that applies an operation (ie + - * /) over two elements." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4cc7f805-0887-4422-b6b7-3d591d0df1fb", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "150e59553964d970460cd9ec831a3740", + "grade": false, + "grade_id": "cell-8c5106f02f243455", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# YOUR CODE HERE\n", + "raise NotImplementedError()" + ] + }, + { + "cell_type": "markdown", + "id": "e68bdf7c-ca08-4553-9874-8bd9038fd4b5", + "metadata": {}, + "source": [ + "Solution in pseudo-code:\n", + "- Split the input expression in to a list of tokens\n", + "- If not an operator\n", + " - Add the value to the stack\n", + "- If an operator \n", + " - Make sure there is enough parameters `a` and `b`\n", + " - Pop `a` and `b`\n", + " - Apply `apply_operator` on `a` and `b`\n", + " - Store the result in the stack" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e792c90d-1b38-47f5-9879-399debc934b9", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "73960d3c6b85c2efc0ad8e298e2649b7", + "grade": false, + "grade_id": "cell-e9236618b265b34f", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def evaluate_postfix(expression):\n", + "# YOUR CODE HERE\n", + "raise NotImplementedError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea6e4840-1b7e-4265-b37d-e8c45ea6b3ed", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "postfix_expression = \"3 4 + 2 *\"\n", + "print(evaluate_postfix(postfix_expression))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0dc4dff8-089b-46a6-a08d-f53ee2fe72c3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "assert evaluate_postfix(\"3 4 + 2 *\") == 14\n", + "assert evaluate_postfix(\"4 2 3 5 * + *\") == 68 # (4 * (2 + (3 * 5))\n", + "assert evaluate_postfix(\"8 4 / 6 2 * +\") == 14 # ((8 / 4) + (6 * 2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18f4fdcb-50be-4219-b14c-1e9a902e22db", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}