diff --git a/01-data-structures-complexity-exercices.ipynb b/01-data-structures-complexity-exercises.ipynb
similarity index 98%
rename from 01-data-structures-complexity-exercices.ipynb
rename to 01-data-structures-complexity-exercises.ipynb
index b46fdf73fcba8c5fae1186c007f213a51fcfafdb..de69cd4c5ad1b13fd3f0174560b7b1cac9776cdb 100644
--- a/01-data-structures-complexity-exercices.ipynb
+++ b/01-data-structures-complexity-exercises.ipynb
@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "markdown",
-   "id": "608c95b1",
+   "id": "136ec072",
    "metadata": {},
    "source": [
     "# UE5 Fundamentals of Algorithms\n",
@@ -23,7 +23,7 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "a934feef",
+   "id": "b8c8e619",
    "metadata": {},
    "outputs": [],
    "source": [
@@ -33,7 +33,7 @@
   },
   {
    "cell_type": "markdown",
-   "id": "b498a6a2",
+   "id": "986b50e4",
    "metadata": {},
    "source": [
     "---"
@@ -74,7 +74,7 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "761a1dba-a197-4206-92a2-78920211f9f1",
+   "id": "b54157fc-f0d5-4689-bf2b-344a608bc5a9",
    "metadata": {
     "tags": []
    },
diff --git a/01-introduction.ipynb b/01-introduction.ipynb
index b6070ed5cefbcfd06db81e7ac9d15ad9680e644e..5f11e83a5bcebc413720829ae31260e885253252 100644
--- a/01-introduction.ipynb
+++ b/01-introduction.ipynb
@@ -331,7 +331,7 @@
    "source": [
     "### Exercice: Leap year\n",
     "\n",
-    "Write a function `is_leap_year` that takes a year as input and returns `True` if it's a leap year and `False``\n",
+    "Write a function `is_leap_year` that takes a year as input and returns `True` if it's a leap year and `False`\n",
     " otherwise. The function follows the rules for leap year determination:\n",
     "\n",
     "- A year that is divisible by 4 is a leap year.\n",
@@ -1530,7 +1530,7 @@
     }
    },
    "source": [
-    "### Exercice: remove duplicatas from a list (using dicts)\n",
+    "### Exercice: detect duplicates from a list (using dicts)\n",
     "\n",
     "Write an algorithm validates the following:\n",
     "\n",
@@ -2176,14 +2176,6 @@
     "plt.grid()\n",
     "plt.show()"
    ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "a3c54d0d",
-   "metadata": {},
-   "outputs": [],
-   "source": []
   }
  ],
  "metadata": {
diff --git a/02-recursion-exercises.ipynb b/02-recursion-exercises.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..09f693bc94c760e53416868a7624f5cc95adff8f
--- /dev/null
+++ b/02-recursion-exercises.ipynb
@@ -0,0 +1,1135 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "996ed570",
+   "metadata": {},
+   "source": [
+    "# UE5 Fundamentals of Algorithms\n",
+    "## Exercices\n",
+    "### Ecole Centrale de Lyon, Bachelor of Science in Data Science for Responsible Business\n",
+    "#### [Romain Vuillemot](https://romain.vuillemot.net/)\n",
+    "\n",
+    "Before you turn this problem in:\n",
+    "- make sure everything runs as expected. \n",
+    "    - first, **restart the kernel** (in the menubar, select Kernel$\\rightarrow$Restart) \n",
+    "    - then **run all cells** (in the menubar, select Cell$\\rightarrow$Run All).\n",
+    "- make sure you fill in any place that says `YOUR CODE HERE` or \"YOUR ANSWER HERE\"\n",
+    "- remove `raise NotImplementedError()` to get started with your answer\n",
+    "- bonus points (at the end of this notebook) are optionals\n",
+    "- write your name (and collaborators as a list if any) below:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "a0151651",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ID = \"\"\n",
+    "COLLABORATORS_ID = []"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "86da338c",
+   "metadata": {},
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a4e4fad3",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Recursion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a8adef9b",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "skip"
+    }
+   },
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0dfe1da3-b50b-49c0-aaff-483616e13863",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "list_complexities = [\"O(1)\", \"O(log(n))\", \"O(n)\", \"O(n^2)\", \"O(nlog(n))\", \"O(n^3)\", \"O(2^n)\", \"O(n!)\", \"O(n^n)\"]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "568202fd",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### Exercise 0: Find the maximum value in a list (iterative)\n",
+    "\n",
+    "Write a function `find_maximum_iterative` that takes a list of numbers as input and returns the maximum value in the list. For this question, you are  not allowed to use built-in functions like `max()`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "431fe8c1-91d1-40f3-a7a4-f4a3770a4a01",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "8b23d599da9ca2bdba48b9bcdd6e1165",
+     "grade": false,
+     "grade_id": "find_maximum_iterative",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def find_maximum_iterative(L):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f6baae3c-3660-4add-ab4b-48016cba3030",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "find_maximum_iterative([1, 3, 5, 7, 9])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e68b3e9a-418f-4950-9f27-18bb0fe90794",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "9cb3441fa27dd28ce74e368375de8080",
+     "grade": true,
+     "grade_id": "correct_find_maximum_iterative",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert find_maximum_iterative([1, 3, 5, 7, 9]) == 9\n",
+    "assert find_maximum_iterative([-1, -5, -3]) == -1\n",
+    "assert find_maximum_iterative([42]) == 42\n",
+    "assert find_maximum_iterative([4, 8, 8, 2, 7]) == 8\n",
+    "assert find_maximum_iterative([-10, -5, -8, -2, -7]) == -2"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "612dc873-419b-42c5-be36-0accd03ffa79",
+   "metadata": {},
+   "source": [
+    "### Exercise 1: Find the maximum value in a list (recursive)\n",
+    "\n",
+    "Write a recursive version of the previous function; you may use the `max()` function for the recursive call."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "07668fd8",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "fcd4348ffdf05fa800f15e7dba033d8e",
+     "grade": false,
+     "grade_id": "find_maximum_recursive",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def find_maximum_recursive(L):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f9784710-4b2b-434c-bc47-da46fa410749",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "find_maximum_recursive([1, 3, 5, 7, 9])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "9b0161f8-0539-4e5e-921c-1886e61c0783",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "1aae7ba6a868f7afd015deedcdf48aa4",
+     "grade": true,
+     "grade_id": "correct_find_maximum_recursive",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert find_maximum_iterative([-10, -5, -8, -2, -7]) == find_maximum_recursive([-10, -5, -8, -2, -7])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "005efd41-baa1-4505-b80e-3644d61ea094",
+   "metadata": {},
+   "source": [
+    "### Exercise 2: Sum of digits"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "de424156-0b9b-41d0-8e38-ce335f35cec0",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "3872f4f922847e273bc5a45cd425c458",
+     "grade": false,
+     "grade_id": "sum_of_digits",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def sum_of_digits(n):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "cec0caca-cb2c-4e4d-b004-27b3cf2ff611",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "sum_of_digits(10)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "bf276ca2-48ed-4e87-80f2-776f54b7062b",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "feb0a5b734f6734920bfec23da86992b",
+     "grade": true,
+     "grade_id": "correct_sum_of_digits",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert sum_of_digits(10) == sum_of_digits(100000)\n",
+    "assert sum_of_digits(0) == 0\n",
+    "assert sum_of_digits(123) == 6"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e2de630a-f9bd-4d45-959b-430e34cc9044",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "### Exercise 3: Calculate the power"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "abca03a0-7bcd-4ee6-b109-ff2f2da52bb6",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "c8c385784b4dd53e96c693511e7a2e80",
+     "grade": false,
+     "grade_id": "power",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def power(base, exponent):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "abddd3b1-f75f-4cb6-a09e-54eed489c5b0",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "power(2, 10)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "8a6605fe-4f6f-45de-84a3-7601e2e2e6f6",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "1deb1e7cdc63de1900c5375bf6debf2a",
+     "grade": true,
+     "grade_id": "correct_power",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert power(2, 10) == 1024\n",
+    "assert power(2, 0) == 1\n",
+    "assert power(5, 3) == 125"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "715100d3-fc21-49b9-a66d-b5243b4a279d",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "### Exercise 4: Reverse a string"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ddc9826a-0863-4777-a08d-81b66652b5a5",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "762d91a747e5399677a26e44c5d8a041",
+     "grade": false,
+     "grade_id": "reverse_string",
+     "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": "13acad7e-d03c-4ea6-ad86-baf02e0910eb",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "reverse_string(\"Romain\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "453c8e04-6cd9-4581-a206-dd479b6115cd",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "d42cbfb82df47fb4eb82e1530fa8f3cb",
+     "grade": true,
+     "grade_id": "correct_reverse_string",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert reverse_string(\"\") == \"\"\n",
+    "assert reverse_string(\"AA\") == \"AA\"\n",
+    "assert reverse_string(\"ABC\") == \"CBA\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "159b6d78-03ae-4cf8-8545-e822b7160b32",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def iterative_reverse_string(s):\n",
+    "    reversed_str = \"\"\n",
+    "    for char in s:\n",
+    "        reversed_str = char + reversed_str\n",
+    "    return reversed_str"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "43e10b0c",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5ab8f3c9-ddee-45ab-a013-fdd67d9853e0",
+   "metadata": {},
+   "source": [
+    "### Example 5: convert an interative suite into a recursive tail function"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "219add7f",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def sequence(n):\n",
+    "    u = 1\n",
+    "    while n > 0:\n",
+    "        u = 2 * u + 1\n",
+    "        n -= 1\n",
+    "    return u"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0787df24-8234-4286-b910-5f9e456dd279",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "print(\"The result is {}\".format(sequence(3)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "9c17cf1b-6d05-4589-af2b-c05cfcc33202",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "2137e4ccdef7bccaa7b7ed6b52f305a8",
+     "grade": false,
+     "grade_id": "sequence_recursive_tail",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def sequence_recursive_tail(n):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "43507c43-de61-414d-b389-c0a771ad9e0c",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "print(\"The result is still {}\".format(sequence_recursive_tail(3)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "dd923b7c-0cab-4678-8dc3-aad2ab9b25f9",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "c465dc72b44f305c781da5cf50e4c934",
+     "grade": true,
+     "grade_id": "correct_sequence_recursive_non_tail",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "slideshow": {
+     "slide_type": "slide"
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert sequence_recursive_tail(3) == 15"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "3c28b36a",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### Example 6: check if a word is an annagram\n",
+    "\n",
+    "Check if a word can be read backwards."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "51bb3d08",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "1edb53556b907062a6d2f29282317e03",
+     "grade": false,
+     "grade_id": "annagram_rec",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def annagram_rec(word):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0c279628-9b96-4687-8e20-a954ab646e0f",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "annagram_rec(\"laval\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "cf6fa61a-7c6f-4a32-96c2-b9fd50deacc6",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "22a5df98d007ceb58975b5877958e3f8",
+     "grade": true,
+     "grade_id": "correct_annagram_rec",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert annagram_rec(\"\")\n",
+    "assert annagram_rec(\"AA\")\n",
+    "assert not annagram_rec(\"ABC\")\n",
+    "assert annagram_rec(\"ABA\")\n",
+    "assert annagram_rec(\"LAVAL\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "798c2875-7940-488a-8458-ad08f6a71c70",
+   "metadata": {},
+   "source": [
+    "### Example 7: Calculate GCD\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "48c65c83-be0c-41c4-8c04-1d29ac4415cb",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def iterative_gcd(a, b):\n",
+    "    while b:\n",
+    "        a, b = b, a % b\n",
+    "    return a"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "bf6e1a76",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "45353cb0fdd92b57e6f6f1739ed430b3",
+     "grade": false,
+     "grade_id": "recursive_gcd",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def recursive_gcd(a, b):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "4f1feace",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "recursive_gcd(10, 2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e6ff1765-ff4b-49a5-80d3-684d2627e961",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "ed3ae90c2a4be5ff93a5d68b688f0f96",
+     "grade": true,
+     "grade_id": "correct_recursive_gcd",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert iterative_gcd(10, 2) == recursive_gcd(10, 2)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d8b05edf-9536-4fc1-bfcc-ddbbeee426fc",
+   "metadata": {},
+   "source": [
+    "### Example 8: Check if a list is sorted"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1661dfb5-88f2-411f-8fe2-63bbaa29ce72",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "9fcedc9d6262baf07013d0b6f4e8175d",
+     "grade": false,
+     "grade_id": "calculate_average_recursive",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def is_sorted(lst):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0c5c72c6-3237-4f98-ab96-50a1838b833f",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "is_sorted([1, 2, 3, 4, 5])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "9f18b6b7-d980-4a72-a2a8-3aa201003d21",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "9cdabb05d7be086c1b769672a158fdc6",
+     "grade": true,
+     "grade_id": "correct_calculate_average_recursive",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert is_sorted([2, 3])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "79eef392-1d3d-46c0-aeee-ac805686e6f1",
+   "metadata": {},
+   "source": [
+    "### Example 9: Check for prime number"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ac374a08-11c9-47e6-ba11-419549911266",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "58fec5e697f40d4e1934bdce3ae87647",
+     "grade": false,
+     "grade_id": "is_prime_recursive",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def is_prime_recursive(n, divisor=2):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "996fc91f",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "is_prime_recursive(3)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5be1051c-3b60-4810-b855-6f8575ad6380",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "f571ff3e3a5bc53ffbc828b255bfb6cb",
+     "grade": true,
+     "grade_id": "correct_is_prime_recursive",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert is_prime_recursive(3) "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5423682d-c31f-4a8d-9a0f-6812de7b1ae3",
+   "metadata": {},
+   "source": [
+    "### Example 10: Count occurrences of a given element in a list"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "cfeb0ad0-ed82-499e-9af3-64923291a0e7",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "01c4970fffe483944b93049b5d8404a0",
+     "grade": false,
+     "grade_id": "count_occurrences",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def count_occurrences(arr, target, index=0):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "49daec07-00b3-412e-ad44-5bafadbd9f36",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "count_occurrences([1, 2, 3, 4, 2, 2, 5, 6, 2], 2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "14a2eb85-1126-4506-93bb-4bf624d046b6",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "5df4afd6ed2f7dfd102b8c21f8ced2e7",
+     "grade": true,
+     "grade_id": "correct_count_occurrences",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert count_occurrences([1, 2, 3, 4, 2, 2, 5, 6, 2], 2) == 4"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "bb1784f5-2426-4661-aa13-dba96743ceb5",
+   "metadata": {},
+   "source": [
+    "# Bonus points"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "7fdcd705-dc0b-4614-8e27-9ba62f8fe442",
+   "metadata": {},
+   "source": [
+    "### Exercise 1: Find the maximum value in a list (iterative)\n",
+    "\n",
+    "Check that an empty lists raises a `ValueError` exception with a `\"The list is empty.\"` message."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f9334f32-f760-46c0-a649-c82f267aba5b",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "try:\n",
+    "    result = find_maximum_iterative([])\n",
+    "    assert False, \"Exception not raised\"\n",
+    "except ValueError as e:\n",
+    "    assert str(e) == \"The list is empty.\", f\"Expected error message: 'The list is empty.' but got '{str(e)}'\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c121315a-4aaa-4e04-912f-73f56555be56",
+   "metadata": {},
+   "source": [
+    "### Exercise 1: Find the maximum value in a list (recursive)\n",
+    "\n",
+    "Witout using the built-in `max` function"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "153e3f05-7598-4920-bc8d-8943cb75e5a8",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# checks if a function uses another function, eg \"max\"\n",
+    "import inspect\n",
+    "\n",
+    "def calls_builtin_max(func):\n",
+    "    source_code = inspect.getsource(func)\n",
+    "    return 'max(' in source_code\n",
+    "\n",
+    "def my_function(lst):\n",
+    "    return max(lst)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "775b7e32-a5ae-431b-9987-fcd3671fd022",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def find_maximum_recursive_no_max_func(L): \n",
+    "    if not L:\n",
+    "        raise ValueError(\"The list is empty.\")\n",
+    "    \n",
+    "    if len(L) == 1:\n",
+    "        return L[0]\n",
+    "    \n",
+    "    rest_max = find_maximum_recursive(L[1:])\n",
+    "    return L[0] if L[0] > rest_max else rest_max"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f76ed657-3288-4b36-9175-21168d2eb761",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert not calls_builtin_max(find_maximum_recursive_no_max_func)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "bbe7023a-aabd-489d-bae6-3b71566e22ef",
+   "metadata": {},
+   "source": [
+    "# Additional tests (do not change)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b8bc657e-d491-4851-aa8c-ac2f2eac0841",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1c73ad0e-ddc9-483d-85a1-f2a65d04f30b",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert calls_builtin_max(my_function)\n",
+    "assert not calls_builtin_max(find_maximum_iterative)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "8ce960f5-08da-449e-9e6f-dae215bc1b6a",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# generates more examples for a given function\n",
+    "def gen_examples(fnct, n=10):\n",
+    "    return [fnct(i) for i in range(0, n)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "d601b2f3-c33b-4ed2-81be-639ce1ffab76",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1f252530-7817-444c-ae10-d7b3bca87f2d",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0976f7c2-4375-4d76-a6c1-9e729a6c8aeb",
+   "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
+}
diff --git a/02-recursion.ipynb b/02-recursion.ipynb
index 96f87fa998c46344f9d799e6c3c7f8d493ddb0d1..4ce9a3d98ad76ab66255042c7a29b778517af5d6 100644
--- a/02-recursion.ipynb
+++ b/02-recursion.ipynb
@@ -66,6 +66,64 @@
     "* Similarity to proof by induction."
    ]
   },
+  {
+   "cell_type": "markdown",
+   "id": "1168f89b",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### Example 0: countdown"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "id": "687dc73a",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "5\n",
+      "4\n",
+      "3\n",
+      "2\n",
+      "1\n",
+      "Blastoff!\n"
+     ]
+    }
+   ],
+   "source": [
+    "def countdown(n):\n",
+    "    if n <= 0: # base case\n",
+    "        print(\"Blastoff!\")\n",
+    "    else:\n",
+    "        print(n)\n",
+    "        countdown(n - 1) # recursive call\n",
+    "\n",
+    "countdown(5)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "8d305f45",
+   "metadata": {},
+   "source": [
+    "Here's how the countdown(5) call would work:\n",
+    "<pre>\n",
+    "countdown(5) prints 5 and calls countdown(4)\n",
+    "countdown(4) prints 4 and calls countdown(3)\n",
+    "countdown(3) prints 3 and calls countdown(2)\n",
+    "countdown(2) prints 2 and calls countdown(1)\n",
+    "countdown(1) prints 1 and calls countdown(0)\n",
+    "countdown(0) prints \"Blastoff!\" and returns without making another recursive call.\n",
+    "</pre>"
+   ]
+  },
   {
    "cell_type": "markdown",
    "id": "0f552254",
@@ -454,7 +512,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
+   "execution_count": 42,
    "id": "021f2066",
    "metadata": {},
    "outputs": [],
@@ -462,12 +520,12 @@
     "def print_desc(n):\n",
     "    if n > 0:\n",
     "        print(\" \" * n, \"  n= \" , n ,\" brefore recursive call\")\n",
-    "        ecrire_desc (n - 1)"
+    "        print_desc (n - 1)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 32,
+   "execution_count": 43,
    "id": "ed36ce86",
    "metadata": {},
    "outputs": [
@@ -476,8 +534,8 @@
      "output_type": "stream",
      "text": [
       "      n=  3  brefore recursive call\n",
-      "     n=  2  avant l'appel récursif\n",
-      "    n=  1  avant l'appel récursif\n"
+      "     n=  2  brefore recursive call\n",
+      "    n=  1  brefore recursive call\n"
      ]
     }
    ],
@@ -487,7 +545,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 33,
+   "execution_count": 44,
    "id": "5223a19b",
    "metadata": {
     "slideshow": {
@@ -498,13 +556,13 @@
    "source": [
     "def print_asc(n) :\n",
     "    if n > 0:\n",
-    "        ecrire_asc(n - 1)    \n",
+    "        print_asc(n - 1)    \n",
     "        print(\" \" * n, \"  n= \" , n ,\" after recrusive call\")"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
+   "execution_count": 45,
    "id": "a4262dee",
    "metadata": {},
    "outputs": [
@@ -512,8 +570,8 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "    n=  1  après l'appel récursif\n",
-      "     n=  2  après l'appel récursif\n",
+      "    n=  1  after recrusive call\n",
+      "     n=  2  after recrusive call\n",
       "      n=  3  after recrusive call\n"
      ]
     }
diff --git a/03-lists-search-sort-exercises.ipynb b/03-lists-search-sort-exercises.ipynb
index 3d5c261bef217345cb2f9c87138028f365855172..ad1a42338c11168e2ea4e7e157da587798ab075b 100644
--- a/03-lists-search-sort-exercises.ipynb
+++ b/03-lists-search-sort-exercises.ipynb
@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "markdown",
-   "id": "d8056b8c",
+   "id": "5cbf5ca9",
    "metadata": {},
    "source": [
     "# UE5 Fundamentals of Algorithms\n",
@@ -23,7 +23,7 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "9c5894f5",
+   "id": "43da1f45",
    "metadata": {},
    "outputs": [],
    "source": [
@@ -33,7 +33,7 @@
   },
   {
    "cell_type": "markdown",
-   "id": "838b13ee",
+   "id": "4d0c6ee6",
    "metadata": {},
    "source": [
     "---"
@@ -55,14 +55,26 @@
     "---"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1095285f-26e2-43ce-a1c5-9358c5256a0b",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "list_complexities = [\"O(1)\", \"O(log(n))\", \"O(n)\", \"O(n^2)\", \"O(nlog(n))\", \"O(n^3)\", \"O(2^n)\", \"O(n!)\", \"O(n^n)\"]"
+   ]
+  },
   {
    "cell_type": "markdown",
    "id": "9d813205-b709-42ab-b414-6f3fc947022a",
    "metadata": {},
    "source": [
-    "## Exerccise 1: Search in a list with an odd index\n",
+    "## Exercise 1: Search in a list with an odd index\n",
     "\n",
-    "Write a Python function `search_list(L, v)` that takes a list `L` and a target element `v` as input. The function should return the index of the first occurrence of the target element in the list `L`. If the target element is not in the list, return -1. The target index should also be of an odd value (eg 0, 2, 4, ..)."
+    "_Write a Python function `search_list(L, v)` that takes a list `L` and a target element `v` as input. The function should return the index of the first occurrence of the target element in the list `L`._"
    ]
   },
   {
@@ -95,19 +107,6 @@
    "execution_count": null,
    "id": "f280eeea-4812-4a30-80b5-3fe1cafa9283",
    "metadata": {
-    "deletable": false,
-    "editable": false,
-    "nbgrader": {
-     "cell_type": "code",
-     "checksum": "e508e1baca64296eb559208993ee6289",
-     "grade": true,
-     "grade_id": "correct_search_list",
-     "locked": true,
-     "points": 1,
-     "schema_version": 3,
-     "solution": false,
-     "task": false
-    },
     "tags": []
    },
    "outputs": [],
@@ -120,6 +119,19 @@
    "execution_count": null,
    "id": "423d2637-8bd6-4e8f-95ff-2765dae5bce7",
    "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "68b51ac31cc882ccdf9200c444d4e30d",
+     "grade": true,
+     "grade_id": "correct_correct_search_list",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
     "tags": []
    },
    "outputs": [],
@@ -137,9 +149,9 @@
    "id": "6d8dc6cd-aad0-42a9-b768-6a1a5289e354",
    "metadata": {},
    "source": [
-    "## Exerccise 2: Sort a list of tuples\n",
+    "## Exercise 2: Sort a list of tuples\n",
     "\n",
-    "Given a list of lists of length N, sort by the N-th element of the list"
+    "_Given a list of lists of length N, sort by the N-th element of the list._"
    ]
   },
   {
@@ -150,7 +162,7 @@
     "deletable": false,
     "nbgrader": {
      "cell_type": "code",
-     "checksum": "d36956e43a1d9a594625212c58f4560a",
+     "checksum": "18319fc9882c760de9d2f2dde25e2c76",
      "grade": false,
      "grade_id": "sort_list_of_lists_by_nth_element",
      "locked": false,
@@ -164,8 +176,7 @@
    "source": [
     "def sort_list_of_lists_by_nth_element(list_of_lists, N):\n",
     "    # YOUR CODE HERE\n",
-    "    raise NotImplementedError()\n",
-    "# Example usage:\n"
+    "    raise NotImplementedError()"
    ]
   },
   {
@@ -222,7 +233,9 @@
    "id": "0bbda1ba-a5e7-4a1d-a742-84d0215b1e24",
    "metadata": {},
    "source": [
-    "## Exerccise 3: Access a list element"
+    "## Exercise 3: Access a list element\n",
+    "\n",
+    "_Given an input list `L`, and `index` value, access a given `key` and return the value._"
    ]
   },
   {
@@ -273,7 +286,7 @@
     "editable": false,
     "nbgrader": {
      "cell_type": "code",
-     "checksum": "c77eefc574735feb146d00c86553b601",
+     "checksum": "efa0cb4d52536298b425a5e9d5154374",
      "grade": true,
      "grade_id": "correct_access_dict_element",
      "locked": true,
@@ -288,14 +301,8 @@
    "source": [
     "example_list = [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}]\n",
     "assert access_dict_element(example_list, 0, 'name') == 'Alice'\n",
-    "\n",
-    "# Example 2: Accessing a non-existing key in a dictionary at a valid index\n",
     "assert access_dict_element(example_list, 1, 'city') is None\n",
-    "\n",
-    "# Example 3: Accessing an index that is out of range\n",
     "assert access_dict_element(example_list, 2, 'name') is None\n",
-    "\n",
-    "# Example 4: Accessing a valid index but with a key that doesn't exist\n",
     "assert access_dict_element(example_list, 0, 'city') is None"
    ]
   },
@@ -306,9 +313,9 @@
     "tags": []
    },
    "source": [
-    "## Exerccise 4: Remove Elements from a List\n",
+    "## Exercise 4: Remove Elements from a List\n",
     "\n",
-    "Write a Python function `remove_elements(L, condition)` that takes a list `L` and a function `condition` as input. The `condition` is a function that accepts an element from the list as its argument and returns a boolean value. The function `remove_elements` should remove all elements from the list for which the `condition` function returns `True`."
+    "_Write a Python function `remove_elements(L, condition)` that takes a list `L` and a function `condition` as input._"
    ]
   },
   {
@@ -372,7 +379,7 @@
     "editable": false,
     "nbgrader": {
      "cell_type": "code",
-     "checksum": "7d18e8b7e4619abfc3e78fb2f2801892",
+     "checksum": "d60a1be7322087e5612fb15fc5677539",
      "grade": true,
      "grade_id": "correct_remove_elements",
      "locked": true,
@@ -385,17 +392,14 @@
    },
    "outputs": [],
    "source": [
-    "# Test 1: Remove elements greater than 10\n",
     "test_list_1 = [12, 5, 18, 9, 25, 3, 15]\n",
     "remove_elements(test_list_1, lambda x: x > 10)\n",
-    "assert test_list_1 == [5, 9, 3]\n",
+    "assert test_list_1 == [5, 9, 3], \"Remove greater than 30\"\n",
     "\n",
-    "# Test 2: Remove negative elements\n",
     "test_list_2 = [-3, 7, -9, 2, 0, -1, 8]\n",
     "remove_elements(test_list_2, lambda x: x < 0)\n",
-    "assert test_list_2 == [7, 2, 0, 8]\n",
+    "assert test_list_2 == [7, 2, 0, 8], \"Remove negative elements\"\n",
     "\n",
-    "# Test 3: Remove elements based on a custom condition\n",
     "def custom_condition(x):\n",
     "    return x % 3 == 0\n",
     "test_list_3 = [1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
@@ -408,7 +412,7 @@
     "\n",
     "test_list_5 = [10, 20, 30, 40]\n",
     "remove_elements(test_list_5, lambda x: False)\n",
-    "assert test_list_5 == [10, 20, 30, 40], \"No elements to remove\""
+    "assert test_list_5 == [10, 20, 30, 40], \"No element to remove\""
    ]
   },
   {
diff --git a/03-lists-search-sort.ipynb b/03-lists-search-sort.ipynb
index 380986258b08a8025f158a66146ef2c90535ffbc..b1084b9cd440f98ae9fc14c507e8fcc85612c262 100644
--- a/03-lists-search-sort.ipynb
+++ b/03-lists-search-sort.ipynb
@@ -24,25 +24,6 @@
     "<center><img  src=\"figures/Logo_ECL.png\" style=\"width:300px\"></center>\n"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "id": "6341504d",
-   "metadata": {
-    "slideshow": {
-     "slide_type": "skip"
-    }
-   },
-   "source": [
-    "---\n",
-    "TODO\n",
-    "- \n",
-    "- tp-pythonneries.pdf\n",
-    "Static and dynamic arrays\n",
-    "Singly linked lists\n",
-    "Doubly linked lists\n",
-    "Circular linked lists"
-   ]
-  },
   {
    "cell_type": "markdown",
    "id": "fbbc2f0d",
@@ -130,14 +111,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 1,
    "id": "33da6137",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1\n",
+      "2\n",
+      "3\n"
+     ]
+    }
+   ],
    "source": [
     "L = [1, 2, 3]\n",
     "\n",
-    "for val in tab:\n",
+    "for val in L:\n",
     "    print(val)"
    ]
   },
@@ -155,10 +146,19 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 2,
    "id": "05a3d562",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "True\n",
+      "False\n"
+     ]
+    }
+   ],
    "source": [
     "def estordonnee(liste):\n",
     "\n",
@@ -187,7 +187,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 3,
    "id": "5aad3402",
    "metadata": {},
    "outputs": [],
@@ -205,24 +205,43 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 4,
    "id": "37c3b4a7",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1.5497207641601563e-07"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
     "compute_average(20)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 5,
    "id": "9c4be228",
    "metadata": {
     "slideshow": {
      "slide_type": "-"
     }
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1, 2, 99, 100, 3, 4, 5]\n"
+     ]
+    }
+   ],
    "source": [
     "my_list = [1, 2, 3, 4, 5]\n",
     "insert_elements = [99, 100]\n",
@@ -246,7 +265,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 6,
    "id": "8a5dd42f",
    "metadata": {
     "nbgrader": {
@@ -269,7 +288,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 7,
    "id": "a3e4ed1f",
    "metadata": {
     "nbgrader": {
@@ -282,7 +301,15 @@
      "task": false
     }
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "3 found at index 2.\n"
+     ]
+    }
+   ],
    "source": [
     "L = [1, 2, 3, 4, 5]\n",
     "element_to_find = 3\n",
@@ -323,22 +350,20 @@
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": 22,
-   "id": "0d5eeb2c",
+   "cell_type": "markdown",
+   "id": "57327e04",
    "metadata": {
     "slideshow": {
      "slide_type": "subslide"
     }
    },
-   "outputs": [],
    "source": [
     "### Example: Binary search (pseudo code)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 10,
    "id": "1197437b",
    "metadata": {
     "slideshow": {
@@ -359,18 +384,17 @@
     "    left, right = 0, len(arr) - 1\n",
     "\n",
     "    while left <= right:\n",
-    "        mid = (left + right) // 2  # Calculate the middle index\n",
+    "        mid = (left + right) // 2 \n",
     "\n",
     "        if arr[mid] == target:\n",
-    "            return mid  # Element found, return its index\n",
+    "            return mid \n",
     "        elif arr[mid] < target:\n",
-    "            left = mid + 1  # Search the right half\n",
+    "            left = mid + 1 \n",
     "        else:\n",
-    "            right = mid - 1  # Search the left half\n",
+    "            right = mid - 1 \n",
     "\n",
-    "    return -1  # Element not found\n",
+    "    return -1  \n",
     "\n",
-    "# Example usage:\n",
     "ordered_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
     "target_element = 5\n",
     "result = binary_search(ordered_list, target_element)\n",
@@ -412,7 +436,7 @@
     }
    },
    "source": [
-    "### All the ways to sort a list "
+    "### Many ways to sort a list "
    ]
   },
   {
@@ -429,48 +453,169 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 36,
    "id": "01e4d112",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]\n"
+     ]
+    }
+   ],
    "source": [
     "numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]\n",
-    "sorted_numbers = sorted(numbers)"
+    "sorted(numbers) # in place operation (changes the original variable)\n",
+    "print(sorted_numbers)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 38,
    "id": "e2c9277a",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[9, 6, 5, 5, 5, 4, 3, 3, 2, 1, 1]\n"
+     ]
+    }
+   ],
    "source": [
     "numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]\n",
-    "numbers.sort(reverse=True)"
+    "numbers.sort(reverse=True) # did not change the original variable\n",
+    "print(numbers)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "id": "26d6dad8",
+   "execution_count": 92,
+   "id": "34975051",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "['date', 'apple', 'cherry', 'banana']\n"
+     ]
+    }
+   ],
+   "source": [
+    "words = ['apple', 'cherry', 'banana', 'date']\n",
+    "sorted_words = sorted(words, key=len)\n",
+    "print(sorted_words)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 93,
+   "id": "7fcf7380",
    "metadata": {},
    "outputs": [],
    "source": [
-    "numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]\n",
-    "numbers.sort()"
+    "import functools"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "id": "34975051",
+   "execution_count": 98,
+   "id": "547f8c13",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['apple', 'banana', 'cherry', 'date']"
+      ]
+     },
+     "execution_count": 98,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "words = ['apple', 'cherry', 'banana', 'date']\n",
+    "sorted(words, key=functools.cmp_to_key(order_by_alphabetical_order))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 95,
+   "id": "357d7c7a",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['apple', 'banana', 'cherry', 'date']"
+      ]
+     },
+     "execution_count": 95,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "words = ['apple', 'cherry', 'banana', 'date']\n",
+    "sorted(words, key=functools.cmp_to_key(lambda x, y: ord(x[0]) - ord(y[0])))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 97,
+   "id": "90102b6a",
    "metadata": {},
    "outputs": [],
    "source": [
-    "words = ['apple', 'banana', 'cherry', 'date']\n",
-    "sorted_words = sorted(words, key=len)"
+    "def order_by_alphabetical_order(a, b):\n",
+    "    return ord(a[0]) - ord(b[0])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 99,
+   "id": "6afa72f9",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1"
+      ]
+     },
+     "execution_count": 99,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "order_by_alphabetical_order(\"cherry\", \"banana\")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": 53,
+   "id": "a0c076fa",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "66"
+      ]
+     },
+     "execution_count": 53,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": []
+  },
   {
    "cell_type": "markdown",
    "id": "ee60b8ff",
@@ -619,6 +764,49 @@
     "    print(item)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "id": "ff445529",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def fib_generator():\n",
+    "    a, b = 0, 1\n",
+    "    while True:\n",
+    "        yield a\n",
+    "        a, b = b, a + b"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "id": "e8aa68b2",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0\n",
+      "1\n",
+      "1\n",
+      "2\n",
+      "3\n",
+      "5\n",
+      "8\n",
+      "13\n",
+      "21\n",
+      "34\n"
+     ]
+    }
+   ],
+   "source": [
+    "fib = fib_generator()\n",
+    "for _ in range(10):\n",
+    "    print(next(fib))"
+   ]
+  },
   {
    "cell_type": "markdown",
    "id": "0a882d1d",
@@ -642,16 +830,6 @@
     "- On the other hand, it requires linear search time (unlike arrays), and can be problematic for implementing a stack.\n"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": 19,
-   "id": "f248b881",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "## Linked list (cont.)"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": 18,
@@ -702,26 +880,23 @@
     "traverse()\n"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "5c865215",
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
   {
    "cell_type": "markdown",
    "id": "28564ab2",
-   "metadata": {},
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
    "source": [
     "## Filter\n",
-    "\n"
+    "\n",
+    "Return a sublist given a criteri"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 11,
    "id": "3012f2e3",
    "metadata": {},
    "outputs": [
@@ -731,7 +906,7 @@
        "[6, 7, 8, 9]"
       ]
      },
-     "execution_count": 9,
+     "execution_count": 11,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -744,20 +919,56 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "id": "5c0860da",
+   "execution_count": 14,
+   "id": "8de20627",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[2, 3]"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
-    "## Map"
+    "[1, 2, 3][1:]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fe92613c",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Map\n",
+    "\n",
+    "Apply a function a list of values"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 12,
    "id": "435094a4",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
     "list(map(lambda x : x * x, x))"
    ]
@@ -765,15 +976,129 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "5575cf08",
+   "id": "fb30b1ce",
    "metadata": {},
    "outputs": [],
    "source": []
   },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "id": "f5b8712a",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "L = [1, 2, 3]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "id": "edfc966b",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "L.append(4)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "id": "f61d0ac8",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[1, 2, 3, 4]"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "L"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "id": "fe60f8fc",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "L = L + [5, 6, 7]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "id": "e30fa183",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "L.extend([2, 4, 5])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "id": "e96a50b2",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[1, 2, 3, 4, [5, 6, 7], 2, 4, 5, 5, 6, 7, 2, 4, 5]"
+      ]
+     },
+     "execution_count": 29,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "L"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "id": "bd7930ff",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "L = [3, 4, 5]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "id": "601e1691",
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "ValueError",
+     "evalue": "10 is not in list",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
+      "Cell \u001b[0;32mIn[34], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mL\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mindex\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m10\u001b[39;49m\u001b[43m)\u001b[49m\n",
+      "\u001b[0;31mValueError\u001b[0m: 10 is not in list"
+     ]
+    }
+   ],
+   "source": [
+    "L.index(10)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "fb30b1ce",
+   "id": "8185d9b9",
    "metadata": {},
    "outputs": [],
    "source": []
diff --git a/04-programming-strategies-exercises.ipynb b/04-programming-strategies-exercises.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..386d6b5d20dfa493a190419bf8d89d26f5d28abc
--- /dev/null
+++ b/04-programming-strategies-exercises.ipynb
@@ -0,0 +1,546 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "1523c46c",
+   "metadata": {},
+   "source": [
+    "# UE5 Fundamentals of Algorithms\n",
+    "## Exercices\n",
+    "### Ecole Centrale de Lyon, Bachelor of Science in Data Science for Responsible Business\n",
+    "#### [Romain Vuillemot](https://romain.vuillemot.net/)\n",
+    "\n",
+    "Before you turn this problem in:\n",
+    "- make sure everything runs as expected. \n",
+    "    - first, **restart the kernel** (in the menubar, select Kernel$\\rightarrow$Restart) \n",
+    "    - then **run all cells** (in the menubar, select Cell$\\rightarrow$Run All).\n",
+    "- make sure you fill in any place that says `YOUR CODE HERE` or \"YOUR ANSWER HERE\"\n",
+    "- remove `raise NotImplementedError()` to get started with your answer\n",
+    "- bonus points (at the end of this notebook) are optionals\n",
+    "- write your name (and collaborators as a list if any) below:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c984c437",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ID = \"\"\n",
+    "COLLABORATORS_ID = []"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "81f8cbf6",
+   "metadata": {},
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e58599e3-9ab7-4d43-bb22-aeccade424ce",
+   "metadata": {},
+   "source": [
+    "# Programming strategies"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "691b3c38-0e83-4bb2-ac90-ef76d2dd9a7a",
+   "metadata": {},
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "9d813205-b709-42ab-b414-6f3fc947022a",
+   "metadata": {},
+   "source": [
+    "## Exercise 1: tribonacci\n",
+    "\n",
+    "Here is an implementation of the Tribonacci sequence (similar to the Fibonacci) defined as:\n",
+    "\n",
+    "$T(n) = T(n-1) + T(n-2) + T(n-3)$\n",
+    "\n",
+    "_Explain the role of the `tab` variable; write some tests._"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f3b233ec-7077-479d-9c04-f1a4c35f3111",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def tribonacci(n: int) -> int:\n",
+    "        \n",
+    "        if(n==0):\n",
+    "            return 0\n",
+    "        if(n==1):\n",
+    "            return 1\n",
+    "        if(n==2):\n",
+    "            return 1\n",
+    "        \n",
+    "        tab=[0 for i in range(n+1)]\n",
+    "        tab[0]=0\n",
+    "        tab[1]=1\n",
+    "        tab[2]=1\n",
+    "        \n",
+    "        for i in range(3, n+1):\n",
+    "            tab[i]=tab[i-1]+tab[i-2]+tab[i-3]\n",
+    "        \n",
+    "        return tab[n]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f280eeea-4812-4a30-80b5-3fe1cafa9283",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "tribonacci(11)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "423d2637-8bd6-4e8f-95ff-2765dae5bce7",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "b833cc54e7ba02d4708b3893c582aae4",
+     "grade": false,
+     "grade_id": "cell-9e7356aa23ccfb4c",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b2b31dca-a19a-46cf-b0de-4feec6afa083",
+   "metadata": {},
+   "source": [
+    "## Exercice 2: find two numbers with a given sum\n",
+    "\n",
+    "_Find two numbers in an array `nums` that add up to a specific target value `target`._"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f5a964df-958e-4758-8ca2-1139c59a7585",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "4dc958b6b1ee7b6ff3ddf02ea4805aea",
+     "grade": false,
+     "grade_id": "two_sum",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def two_sum(nums, target: int):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1cec37b0-5d27-4973-b53a-053a46992c0c",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "print(two_sum([1, 2, 3, 4, 5], 4))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "395cb69f-b99a-4c60-88f5-11216a5ec857",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "dce1654749f72d16fa3d21a731f0a7ff",
+     "grade": true,
+     "grade_id": "correct_two_sum",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert two_sum([2, 7, 11, 15], 9) == [0, 1]  # 2 + 7 = 9\n",
+    "assert two_sum([3, 2, 4], 6) == [1, 2]       # 2 + 4 = 6\n",
+    "assert two_sum([3, 3], 6) == [0, 1]          # 3 + 3 = 6"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "dc4f4361-5dee-4e19-b3fd-d18ea40d341e",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "## Exercice 3: find the minimum distance between two points\n",
+    "\n",
+    "_Given a list of points find the minimum distance between all the pairs of points._\n",
+    "\n",
+    "- write a `dist`function\n",
+    "- define a `closest_point_naive`function using `math.inf`as initial value"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0be305c3-c054-4092-b041-bd7e705e2178",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "ad1d7f9ad703f728fac843c9b6d4cbe1",
+     "grade": false,
+     "grade_id": "cell-8738237c4c6682e4",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "import math\n",
+    "def dist(point1, point2):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c0e25948-eefd-4cb0-a893-c3d5e34ff0ee",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "a5504d9e67deeb2651dfc058b5314bb8",
+     "grade": false,
+     "grade_id": "cell-9ca280911ed42034",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def closest_point_naive(P, n):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "965d8274-470e-4a3e-8b88-60d458de74e2",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "points = [(1, 2), (4, 6), (7, 8), (3, 5)]\n",
+    "closest_point_naive(points, len(points))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5d875175-45c3-4594-a434-23e15cfb88f7",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "17cb3a74f60bcbe305bce69a5b45da65",
+     "grade": true,
+     "grade_id": "cell-618f956021833284",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "points1 = [(1, 2), (4, 6), (0, 0), (0, 0)]\n",
+    "n1 = len(points1)\n",
+    "\n",
+    "result1 = closest_point_naive(points1, n1)\n",
+    "expected_result1 = 0.0 \n",
+    "print(result1)\n",
+    "assert math.isclose(result1, expected_result1, rel_tol=1e-9), f\"Test Case 1 failed: {result1} != {expected_result1}\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "4d521622-f4b7-4859-b501-2583b943d0e7",
+   "metadata": {},
+   "source": [
+    "## Exercice 4: display the minimum distance\n",
+    "\n",
+    "_Update the previous function to take a single list of points `P`as input and return the closest points and draw the line that connects them._"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "a5902565-9c98-482a-8e63-9cc37214beb2",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "from matplotlib import pyplot as plt\n",
+    "import random\n",
+    "\n",
+    "points_count = 10\n",
+    "x = [random.gauss(0, 1) for _ in range(points_count)]\n",
+    "y = [random.gauss(0, 1) for _ in range(points_count)]\n",
+    "\n",
+    "def draw_points(x, y):\n",
+    "    color = \"blue\"\n",
+    "    plt.figure(figsize=(10, 7))\n",
+    "    _ = plt.plot(x, y, '.', markersize=14, color=color)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e35557a8-54cb-4324-b280-4479835685db",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "draw_points(x, y)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "6c504c53-d3fc-44a1-904c-49ceff572638",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "bc0203ebd28b691616fc04b52f0c6240",
+     "grade": false,
+     "grade_id": "closest_point_naive_pair",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def closest_point_naive_pair(P):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()\n",
+    "    return closest_point1, closest_point2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "4266685c-19f9-4d2f-bb71-4d047bb54787",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "832d9b24ce34dec082dff9b7e327c869",
+     "grade": true,
+     "grade_id": "correct_closest_point_naive_pair",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "from matplotlib import pyplot as plt\n",
+    "import random\n",
+    "import math\n",
+    "\n",
+    "points_count = 10\n",
+    "color = \"blue\"\n",
+    "x = [random.gauss(0, 1) for _ in range(points_count)]\n",
+    "y = [random.gauss(0, 1) for _ in range(points_count)]\n",
+    "\n",
+    "points = list(zip(x, y))\n",
+    "\n",
+    "closest_point1, closest_point2 = closest_point_naive_pair(points)\n",
+    "\n",
+    "plt.figure(figsize=(10, 7))\n",
+    "_ = plt.plot(x, y, '.', markersize=14, color=color)\n",
+    "plt.plot([closest_point1[0], closest_point2[0]], [closest_point1[1], closest_point2[1]], '-', color='red', linewidth=2)\n",
+    "\n",
+    "plt.show()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "bcec1dfc-6ce9-4b08-bc1c-f8d0887aa876",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "points1 = [(0, 0), (1, 1), (3, 3), (5, 5)]\n",
+    "closest1 = closest_point_naive_pair(points1)\n",
+    "assert closest1 == ((0, 0), (1, 1))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "52ede988-1834-489d-9cca-e9882e90f9af",
+   "metadata": {},
+   "source": [
+    "## Exercice 5: implement the merge sort\n",
+    "\n",
+    "0. Find a base case\n",
+    "1. Finding the mid of the array \n",
+    "2. Divide the array elements  into 2 halves \n",
+    "3. Sorting the first half and the second half independantly\n",
+    "4. merge by copying arrays into a final one"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b835049a-27a7-4d45-b819-b9e4d813fdcf",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "725597ac005b370c6135a3f1920beb2c",
+     "grade": false,
+     "grade_id": "merge_sort",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def merge_sort(arr): \n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "4ad36fe3-7e9e-4ae8-9df6-f816e24d6c28",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "merge_sort([3, 6, 1])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "85865859-828f-4a6b-aad8-51ba0de8ac5b",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "3ca9c06b9c5d3b2b5728138d821e650c",
+     "grade": true,
+     "grade_id": "correct_merge_sort",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "L = [4, 2, 3]\n",
+    "assert merge_sort(L) == sorted(L)"
+   ]
+  }
+ ],
+ "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
+}
diff --git a/04-programming-strategies.ipynb b/04-programming-strategies.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..4d336d8ab1496013ea85e3f39fe7a2d63a06ee63
--- /dev/null
+++ b/04-programming-strategies.ipynb
@@ -0,0 +1,781 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "90ae134f",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# UE5 Fundamentals of Algorithms\n",
+    "## Lecture 4: Programming strategies\n",
+    "### Ecole Centrale de Lyon, Bachelor of Science in Data Science for Responsible Business\n",
+    "#### Romain Vuillemot\n",
+    "<center><img  src=\"figures/Logo_ECL.png\" style=\"width:300px\"></center>"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b3ce5394",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "# Programming strategies\n",
+    "\n",
+    "> A programming strategy are algorithms aimed at solving a specific problem in a precise manner.\n",
+    "\n",
+    "Examples of Strategies:\n",
+    "\n",
+    "- **Divide and Conquer:** Divide a problem into simpler sub-problems, solve the sub-problems, and then combine the solutions to solve the original problem.\n",
+    "\n",
+    "- **Dynamic Programming:** Solve a problem by breaking it down into sub-problems, calculating and memorizing the results of sub-problems to avoid unnecessary recomputation.\n",
+    "\n",
+    "- **Greedy Algorithm:** Make a series of choices that seem locally optimal at each step to find a solution, with the hope that the result will be globally optimal as well.\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "19c91bb3",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Divide and conquer\n",
+    "\n",
+    "> The **Divide and Conquer** strategy involves breaking a complex problem into smaller, similar subproblems, solving them recursively, and then combining their solutions to address the original problem efficiently.\n",
+    "\n",
+    "1. **Divide:** Divide the original problem into subproblems of the same type.\n",
+    "\n",
+    "2. **Conquer:** Solve each of these subproblems recursively.\n",
+    "\n",
+    "3. **Combine:** Combine the answers appropriately.\n",
+    "\n",
+    "_It is very close to the recursive approach_\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c84c6bdd",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "\n",
+    "### Examples of divide and conquer algorithms:\n",
+    "\n",
+    "- Binary search\n",
+    "- Quick sort and merge sort\n",
+    "- Map Reduce\n",
+    "- Others: Fast multiplication (Karatsuba)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fa188fcb",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Binary search\n",
+    "\n",
+    "_Given a sorted list, find or insert a specific value while keeping the order._\n",
+    "\n",
+    "<img src=\"figures/recherche-dichotomique.png\" style=\"width:500px\">"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "ba8f8ab0",
+   "metadata": {},
+   "source": [
+    "## Quick sort\n",
+    "\n",
+    "<img src=\"figures/quicksort.png\" style=\"height:400px\">"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "2ba80ce1",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Merge sort\n",
+    "\n",
+    "<img src=\"figures/tri-fusion.png\" style=\"width:500px\">"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "68bf754c",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Map reduce\n",
+    "\n",
+    "<img src=\"figures/Mapreduce.png\" style=\"width:700px\">"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5e864f8b",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Map reduce (without map reduce..)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "32ad76f1",
+   "metadata": {},
+   "source": [
+    "_Calculate the sum of squares values from a list of numerical values._"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 47,
+   "id": "0df729b8",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 48,
+   "id": "27efe14e",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[(1, 1), (4, 2), (9, 3), (16, 4), (25, 5), (36, 6), (49, 7), (64, 8), (81, 9), (100, 10)]\n"
+     ]
+    }
+   ],
+   "source": [
+    "result = {}\n",
+    "for num in data:\n",
+    "    square = num * num\n",
+    "    if square in result:\n",
+    "        result[square] += num\n",
+    "    else:\n",
+    "        result[square] = num\n",
+    "\n",
+    "final_result = list(result.items())\n",
+    "\n",
+    "print(final_result)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "68e3c445",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Map reduce (Python)\n",
+    "\n",
+    "_Using a \"combine\" step._"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "id": "e4773ca8",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[(1, [1]), (2, [4]), (3, [9]), (4, [16]), (5, [25]), (6, [36]), (7, [49]), (8, [64]), (9, [81]), (10, [100])]\n"
+     ]
+    }
+   ],
+   "source": [
+    "data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
+    "\n",
+    "def mapper(numbers):\n",
+    "    result = []\n",
+    "    for num in numbers: # calculate the squares\n",
+    "        result.append((num, num * num))\n",
+    "    return result\n",
+    "\n",
+    "def reducer(pairs):\n",
+    "    result = {}\n",
+    "    for key, value in pairs: # sums the squares\n",
+    "        if key in result:\n",
+    "            result[key] += value \n",
+    "        else:\n",
+    "            result[key] = value\n",
+    "    return result.items()\n",
+    "\n",
+    "chunk_size = 2\n",
+    "chunks = [data[i:i+chunk_size] for i in range(0, len(data), chunk_size)]\n",
+    "\n",
+    "mapped_data = [mapper(chunk) for chunk in chunks] # map\n",
+    "\n",
+    "grouped_data = {}# combine\n",
+    "for chunk in mapped_data:\n",
+    "    for key, value in chunk:\n",
+    "        if key in grouped_data:\n",
+    "            grouped_data[key].append(value)\n",
+    "        else:\n",
+    "            grouped_data[key] = [value]\n",
+    "\n",
+    "reduced_data = [reducer(list(grouped_data.items()))] # reduce\n",
+    "\n",
+    "# Flatten the result\n",
+    "final_result = []\n",
+    "for item in reduced_data:\n",
+    "    final_result.extend(item)\n",
+    "\n",
+    "print(final_result)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d6f04202",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Discussion \n",
+    "\n",
+    "- Similarities with recursion by dividing a problem in a sub-problem\n",
+    "\n",
+    "- But with a combination step\n",
+    "\n",
+    "- Can be implemented in a non-recursive way\n",
+    "\n",
+    "- Often a $n log(n)$ complexity"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "67fdbeea",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Greedy algorithms\n",
+    "\n",
+    "> Algorithms that make an optimal choice first, and then stick to it\n",
+    "\n",
+    "Examples:\n",
+    "\n",
+    "- Change-making problem\n",
+    "- Knapsack problem"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "1464792e",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Change-making problem\n",
+    "\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "19852a60",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Coin change (pseudo code)\n",
+    "\n",
+    "1. Sort the coins\n",
+    "\n",
+    "2. Initialize a variable to count coins used\n",
+    "\n",
+    "3. Substrack the number of coins used (if limited)\n",
+    "\n",
+    "4. Continue this process until amount becomes zero.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "8c5e5909",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Coin change (Python)\n",
+    "\n",
+    "_Greedy solution._"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "id": "a5a4633a",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "3\n"
+     ]
+    }
+   ],
+   "source": [
+    "def coin_change_greedy(coins, amount):\n",
+    "    coins.sort(reverse=True)  # Sort the coins in descending order\n",
+    "    \n",
+    "    coin_count = 0\n",
+    "    remaining_amount = amount\n",
+    "    \n",
+    "    for coin in coins:\n",
+    "        while remaining_amount >= coin:\n",
+    "            remaining_amount -= coin\n",
+    "            coin_count += 1\n",
+    "    \n",
+    "    if remaining_amount == 0:\n",
+    "        return coin_count\n",
+    "    else:\n",
+    "        return -1\n",
+    "\n",
+    "coins = [1, 2, 5]\n",
+    "amount = 11\n",
+    "print(coin_change_greedy(coins, amount))  # 3 (11 = 5 + 5 + 1)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "97703194",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Huffman coding"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "6372a46e",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "99042d46",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5cd75ee6",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "id": "1d7cfa02",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Dynamic programming\n",
+    "\n",
+    "> **Dynamic programming** involves breaking down a problem into subproblems, *solving* these subproblems, and *combining* their solutions to obtain the solution to the original problem. The steps are as follows:\n",
+    "\n",
+    "1. Characterize the structure of an optimal solution.\n",
+    "2. Define the value of an optimal solution recursively.\n",
+    "3. Reconstruct the optimal solution from the computations.\n",
+    "\n",
+    "Notes :\n",
+    "- Applies to problems with optimal substructure.\n",
+    "- Also applies to problems where solutions are often interrelated (distinguishing it from divide and conquer).\n",
+    "- Utilizes a memoization approach, involving storing an intermediate solution (e.g., in a table).\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d8a79a3d",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### Examples of dynamic programming algorithms\n",
+    "\n",
+    "- Fibonacci Sequence\n",
+    "- Rod Cutting\n",
+    "- Shortest Path Finding\n",
+    "- Sequence Alignment, Longest Subsequence Finding"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "bedc74a2",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Fibonnacci  (reminder)\n",
+    "\n",
+    "To calculate the $n$-th number in the Fibonacci sequence, which is determined as follows:\n",
+    "\n",
+    "latex\n",
+    "Copy code\n",
+    "$fib(n) = fib(n-1) + fib(n-2)$, $n \\in \\mathbb{N}$\n",
+    "Where the sequence starts with 1, 1, and then continues as 2, 3, 5, 8, 13, 21, and so on, to find the 9th number ($n = 9$).\n",
+    "\n",
+    "Let's calculate the 9th Fibonacci number step by step:\n",
+    "\n",
+    "$fib(1) = 1$\n",
+    "\n",
+    "$fib(2) = 1$\n",
+    "\n",
+    "$fib(3) = fib(2) + fib(1) = 1 + 1 = 2$\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "4ccca6dd",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Fibonnacci  (naive)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "id": "57411e8e",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[0, 1, 1, 2, 3, 5, 8, 13]\n"
+     ]
+    }
+   ],
+   "source": [
+    "def fib(n):\n",
+    "    if n < 2:\n",
+    "        return n\n",
+    "    else:\n",
+    "        return fib(n - 1) + fib(n - 2)\n",
+    "print(list(map(fib, range(8))))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b79f68cf",
+   "metadata": {},
+   "source": [
+    "Call tree (for $n = 6$) :"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b3bca648",
+   "metadata": {},
+   "source": [
+    "<img src=\"figures/fibonacci-tree.png\" style=\"width:400px\">"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a3a595ab",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Fibonnacci (optimized using a lookup table)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "id": "5b1d2bb3",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "fragment"
+    }
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Le nombre de fibonacci est  8\n"
+     ]
+    }
+   ],
+   "source": [
+    "def fib(n, lookup): \n",
+    "  \n",
+    "    # Cas d'arrêt\n",
+    "    if n == 0 or n == 1 : \n",
+    "        lookup[n] = n \n",
+    "  \n",
+    "    # On calcule la valeur si pas déjà calculée\n",
+    "    if lookup[n] is None: \n",
+    "        lookup[n] = fib(n-1 , lookup)  + fib(n-2 , lookup)  \n",
+    "  \n",
+    "    # On renvoie la n-eme valeur\n",
+    "    return lookup[n] \n",
+    "  \n",
+    "def main(): \n",
+    "    n = 6 \n",
+    "    max = 100\n",
+    "    # Initialise la table de cache\n",
+    "    lookup = [None]*(max)\n",
+    "    print(\"Le nombre de fibonacci est \", fib(n, lookup))\n",
+    "    # Le nombre de fibonacci est  8\n",
+    "\n",
+    "if __name__==\"__main__\": \n",
+    "    main() "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f4e93e84",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Rod cutting"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "id": "cffad9ad",
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "SyntaxError",
+     "evalue": "invalid non-printable character U+2000 (2415646412.py, line 2)",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;36m  Cell \u001b[0;32mIn[6], line 2\u001b[0;36m\u001b[0m\n\u001b[0;31m    (3), optimale pour t = (0; 1; 1; 5) ;\u001b[0m\n\u001b[0m    ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid non-printable character U+2000\n"
+     ]
+    }
+   ],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "id": "ca5381d3",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def valeur(decoupe, t):\n",
+    "    s = 0\n",
+    "    for taille in decoupe:\n",
+    "        s += t[taille]\n",
+    "    return s"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "id": "1f4298bc",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "30"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "decoupe = [1, 2, 3, 2]  # Par exemple, une découpe possible\n",
+    "t = [1, 5, 8, 9, 10, 17, 17, 20]\n",
+    "valeur(decoupe, t)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "id": "1ac70348",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def coupe_brute_force(n, t):\n",
+    "    if n == 0:\n",
+    "        return 0\n",
+    "    max_valeur = float('-inf')\n",
+    "    for i in range(1, n + 1):\n",
+    "        valeur_courante = t[i] + coupe_brute_force(n - i, t)\n",
+    "        max_valeur = max(max_valeur, valeur_courante)\n",
+    "    return max_valeur"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "id": "82e44946",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "The maximum value for a rod of length 8 is 22.\n"
+     ]
+    }
+   ],
+   "source": [
+    "lengths = [0, 1, 2, 3, 4, 5, 6, 7, 8]\n",
+    "values = [0, 1, 5, 8, 9, 10, 17, 17, 20]\n",
+    "\n",
+    "# Length of the rod you want to cut\n",
+    "rod_length = 8\n",
+    "\n",
+    "# Call the brute force cutting function\n",
+    "max_value = coupe_brute_force(rod_length, values)\n",
+    "\n",
+    "print(f\"The maximum value for a rod of length {rod_length} is {max_value}.\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "35079643",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "arr = [1, 5, 8, 9, 10, 17, 17, 20] "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "6387dcea",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Valeur maximum de découpe 22 8\n"
+     ]
+    }
+   ],
+   "source": [
+    "INT_MIN = 0\n",
+    "\n",
+    "def cutRod(price, n): \n",
+    "\n",
+    "    # Initialisation tables de cache\n",
+    "    val = [0 for x in range(n+1)] \n",
+    "    val[0] = 0\n",
+    "  \n",
+    "    for i in range(1, n+1): \n",
+    "        max_val = INT_MIN \n",
+    "        for j in range(i): \n",
+    "             max_val = max(max_val, price[j] + val[i-j-1]) \n",
+    "        val[i] = max_val \n",
+    "  \n",
+    "    return val[n] \n",
+    "  \n",
+    "if __name__==\"__main__\": \n",
+    "    arr = [1, 5, 8, 9, 10, 17, 17, 20] \n",
+    "    size = len(arr) \n",
+    "    print(\"Valeur maximum de découpe \" + str(cutRod(arr, size)), len(arr) ) "
+   ]
+  }
+ ],
+ "metadata": {
+  "celltoolbar": "Slideshow",
+  "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
+}
diff --git a/solutions/01-data-structures-complexity-exercises.ipynb b/solutions/01-data-structures-complexity-exercises.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..c365c436ec6fbd5d214cc35ec540216037132d65
--- /dev/null
+++ b/solutions/01-data-structures-complexity-exercises.ipynb
@@ -0,0 +1,240 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "a4e4fad3",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Data Structures and Complexity"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a8adef9b",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "skip"
+    }
+   },
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "827ebb43-1e5d-4756-83ba-97af3e36b6af",
+   "metadata": {},
+   "source": [
+    "_For the following question, if a complexity is needed please pick one in this list_"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "b54157fc-f0d5-4689-bf2b-344a608bc5a9",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "list_complexities = [\"O(1)\", \"O(log(n))\", \"O(n)\", \"O(n^2)\", \"O(nlog(n))\", \"O(n^3)\", \"O(2^n)\", \"O(n!)\", \"O(n^n)\"]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "568202fd",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### Exercise 1: Identify the complexity"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 110,
+   "id": "431fe8c1-91d1-40f3-a7a4-f4a3770a4a01",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def nested_loop_example(arr):\n",
+    "    n = len(arr)\n",
+    "    for i in range(n):\n",
+    "        for j in range(n):\n",
+    "            print(arr[i] + arr[j])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 111,
+   "id": "e68b3e9a-418f-4950-9f27-18bb0fe90794",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "cell-a06bfe9af33fe998",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# nested_loop_example_complexity = ?\n",
+    "### BEGIN SOLUTION\n",
+    "nested_loop_example_complexity = \"O(n^2)\"\n",
+    "### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "612dc873-419b-42c5-be36-0accd03ffa79",
+   "metadata": {},
+   "source": [
+    "### Exercise 2: Identify the complexity"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 101,
+   "id": "76102853-e1f3-4717-8a59-1091195a19eb",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def fibonacci_recursive(n):\n",
+    "    if n <= 1:\n",
+    "        return n\n",
+    "    return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 102,
+   "id": "dead6a52-7996-4eae-9d2a-f75d5d26bbb7",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "cell-34e130eb0c6b7e82",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# fibonacci_recursive_complexity = ?\n",
+    "### BEGIN SOLUTION\n",
+    "fibonacci_recursive_complexity = \"O(n^2)\"\n",
+    "### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "aa4a6ce7-e542-4b23-8a10-ca0bf93de041",
+   "metadata": {},
+   "source": [
+    "### Exercise 3: Identify the complexity"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 103,
+   "id": "70af3e43-8053-49c9-ba58-346a3e915bdb",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def binary_search(arr, target):\n",
+    "    low, high = 0, len(arr) - 1\n",
+    "    while low <= high:\n",
+    "        mid = (low + high) // 2\n",
+    "        if arr[mid] == target:\n",
+    "            return mid\n",
+    "        elif arr[mid] < target:\n",
+    "            low = mid + 1\n",
+    "        else:\n",
+    "            high = mid - 1\n",
+    "    return -1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 97,
+   "id": "9c22866c-b4fc-4228-b0ab-5882d964f5f6",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "cell-ea8595a5923fbb0e",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# binary_searche_complexity = ?\n",
+    "### BEGIN SOLUTION\n",
+    "binary_searche_complexity = \"O(nlog(n))\"\n",
+    "### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "87b4921b-ef55-4083-b4f1-a3ca5bb7b011",
+   "metadata": {},
+   "source": [
+    "### Additional checks (do not change)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 108,
+   "id": "6e8f2878-ce5f-4cd8-a5a5-7bce8f655ab8",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert nested_loop_example_complexity in list_complexities\n",
+    "assert fibonacci_recursive_complexity in list_complexities\n",
+    "assert binary_searche_complexity in list_complexities"
+   ]
+  }
+ ],
+ "metadata": {
+  "celltoolbar": "Slideshow",
+  "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
+}
diff --git a/solutions/02-recursion-exercises.ipynb b/solutions/02-recursion-exercises.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..57912ddc91d787d2ef465d35b515b1701c6fac17
--- /dev/null
+++ b/solutions/02-recursion-exercises.ipynb
@@ -0,0 +1,1203 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "a4e4fad3",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# Recursion"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a8adef9b",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "skip"
+    }
+   },
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "id": "0dfe1da3-b50b-49c0-aaff-483616e13863",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "list_complexities = [\"O(1)\", \"O(log(n))\", \"O(n)\", \"O(n^2)\", \"O(nlog(n))\", \"O(n^3)\", \"O(2^n)\", \"O(n!)\", \"O(n^n)\"]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "568202fd",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### Exercise 0: Find the maximum value in a list (iterative)\n",
+    "\n",
+    "Write a function `find_maximum_iterative` that takes a list of numbers as input and returns the maximum value in the list. For this question, you are  not allowed to use built-in functions like `max()`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "431fe8c1-91d1-40f3-a7a4-f4a3770a4a01",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "find_maximum_iterative",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def find_maximum_iterative(L):\n",
+    "    ### BEGIN SOLUTION    \n",
+    "    if len(L) == 0:\n",
+    "        raise ValueError(\"The list is empty.\")\n",
+    "\n",
+    "    max_val = L[0]\n",
+    "    for num in L:\n",
+    "        if num > max_val:\n",
+    "            max_val = num\n",
+    "    return max_val\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "id": "f6baae3c-3660-4add-ab4b-48016cba3030",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "9"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "find_maximum_iterative([1, 3, 5, 7, 9])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "id": "e68b3e9a-418f-4950-9f27-18bb0fe90794",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_find_maximum_iterative",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert find_maximum_iterative([1, 3, 5, 7, 9]) == 9\n",
+    "assert find_maximum_iterative([-1, -5, -3]) == -1\n",
+    "assert find_maximum_iterative([42]) == 42\n",
+    "assert find_maximum_iterative([4, 8, 8, 2, 7]) == 8\n",
+    "assert find_maximum_iterative([-10, -5, -8, -2, -7]) == -2"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "612dc873-419b-42c5-be36-0accd03ffa79",
+   "metadata": {},
+   "source": [
+    "### Exercise 1: Find the maximum value in a list (recursive)\n",
+    "\n",
+    "Write a recursive version of the previous function; you may use the `max()` function for the recursive call."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "07668fd8",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "find_maximum_recursive",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def find_maximum_recursive(L):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if len(L) == 1:\n",
+    "        return L[0]\n",
+    "    else:\n",
+    "        return max(L[0], find_maximum_recursive(L[1:]))\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "id": "f9784710-4b2b-434c-bc47-da46fa410749",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "9"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "find_maximum_recursive([1, 3, 5, 7, 9])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "id": "9b0161f8-0539-4e5e-921c-1886e61c0783",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_find_maximum_recursive",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert find_maximum_iterative([-10, -5, -8, -2, -7]) == find_maximum_recursive([-10, -5, -8, -2, -7])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "005efd41-baa1-4505-b80e-3644d61ea094",
+   "metadata": {},
+   "source": [
+    "### Exercise 2: Sum of digits"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "id": "de424156-0b9b-41d0-8e38-ce335f35cec0",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "sum_of_digits",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def sum_of_digits(n):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if n < 10:\n",
+    "        return n\n",
+    "    else:\n",
+    "        return n % 10 + sum_of_digits(n // 10)\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "id": "cec0caca-cb2c-4e4d-b004-27b3cf2ff611",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1"
+      ]
+     },
+     "execution_count": 11,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sum_of_digits(10)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "id": "bf276ca2-48ed-4e87-80f2-776f54b7062b",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_sum_of_digits",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert sum_of_digits(10) == sum_of_digits(100000)\n",
+    "assert sum_of_digits(0) == 0\n",
+    "assert sum_of_digits(123) == 6"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e2de630a-f9bd-4d45-959b-430e34cc9044",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "### Exercise 3: Calculate the power"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "id": "abca03a0-7bcd-4ee6-b109-ff2f2da52bb6",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "power",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def power(base, exponent):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if exponent == 0:\n",
+    "        return 1\n",
+    "    else:\n",
+    "        return base * power(base, exponent - 1)\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "id": "abddd3b1-f75f-4cb6-a09e-54eed489c5b0",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1024"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "power(2, 10)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "id": "8a6605fe-4f6f-45de-84a3-7601e2e2e6f6",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_power",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert power(2, 10) == 1024\n",
+    "assert power(2, 0) == 1\n",
+    "assert power(5, 3) == 125"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "715100d3-fc21-49b9-a66d-b5243b4a279d",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "### Exercise 4: Reverse a string"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "id": "ddc9826a-0863-4777-a08d-81b66652b5a5",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "reverse_string",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def reverse_string(s):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if len(s) == 0 or len(s) == 1:\n",
+    "        return s\n",
+    "    else:\n",
+    "        return reverse_string(s[1:]) + s[0]\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "id": "13acad7e-d03c-4ea6-ad86-baf02e0910eb",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'niamoR'"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "reverse_string(\"Romain\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "id": "453c8e04-6cd9-4581-a206-dd479b6115cd",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_reverse_string",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert reverse_string(\"\") == \"\"\n",
+    "assert reverse_string(\"AA\") == \"AA\"\n",
+    "assert reverse_string(\"ABC\") == \"CBA\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "id": "159b6d78-03ae-4cf8-8545-e822b7160b32",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def iterative_reverse_string(s):\n",
+    "    reversed_str = \"\"\n",
+    "    for char in s:\n",
+    "        reversed_str = char + reversed_str\n",
+    "    return reversed_str"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "43e10b0c",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5ab8f3c9-ddee-45ab-a013-fdd67d9853e0",
+   "metadata": {},
+   "source": [
+    "### Example 5: convert an interative suite into a recursive tail function"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "id": "219add7f",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def sequence(n):\n",
+    "    u = 1\n",
+    "    while n > 0:\n",
+    "        u = 2 * u + 1\n",
+    "        n -= 1\n",
+    "    return u"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "id": "0787df24-8234-4286-b910-5f9e456dd279",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "The result is 15\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(\"The result is {}\".format(sequence(3)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "id": "9c17cf1b-6d05-4589-af2b-c05cfcc33202",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "sequence_recursive_tail",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def sequence_recursive_tail(n):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if n == 0:\n",
+    "        return 1\n",
+    "    return 2 * sequence_recursive_tail(n - 1) + 1\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "id": "43507c43-de61-414d-b389-c0a771ad9e0c",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "The result is still 15\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(\"The result is still {}\".format(sequence_recursive_tail(3)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "id": "dd923b7c-0cab-4678-8dc3-aad2ab9b25f9",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_sequence_recursive_non_tail",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "slideshow": {
+     "slide_type": "slide"
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert sequence_recursive_tail(3) == 15"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "3c28b36a",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### Example 6: check if a word is an annagram\n",
+    "\n",
+    "Check if a word can be read backwards."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "id": "51bb3d08",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "annagram_rec",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def annagram_rec(word):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if len(word) < 2: \n",
+    "        return True\n",
+    "    return (word[0] == word[-1]) and annagram_rec(word[1:len(word)-1])\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "id": "0c279628-9b96-4687-8e20-a954ab646e0f",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "True"
+      ]
+     },
+     "execution_count": 26,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "annagram_rec(\"laval\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "id": "cf6fa61a-7c6f-4a32-96c2-b9fd50deacc6",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_annagram_rec",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert annagram_rec(\"\")\n",
+    "assert annagram_rec(\"AA\")\n",
+    "assert not annagram_rec(\"ABC\")\n",
+    "assert annagram_rec(\"ABA\")\n",
+    "assert annagram_rec(\"LAVAL\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "798c2875-7940-488a-8458-ad08f6a71c70",
+   "metadata": {},
+   "source": [
+    "### Example 7: Calculate GCD\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "id": "48c65c83-be0c-41c4-8c04-1d29ac4415cb",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def iterative_gcd(a, b):\n",
+    "    while b:\n",
+    "        a, b = b, a % b\n",
+    "    return a"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "id": "bf6e1a76",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "recursive_gcd",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def recursive_gcd(a, b):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if b == 0:\n",
+    "        return a\n",
+    "    else:\n",
+    "        return recursive_gcd(b, a % b)\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "id": "4f1feace",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "2"
+      ]
+     },
+     "execution_count": 30,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "recursive_gcd(10, 2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "id": "e6ff1765-ff4b-49a5-80d3-684d2627e961",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_recursive_gcd",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert iterative_gcd(10, 2) == recursive_gcd(10, 2)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d8b05edf-9536-4fc1-bfcc-ddbbeee426fc",
+   "metadata": {},
+   "source": [
+    "### Example 8: Check if a list is sorted"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "id": "1661dfb5-88f2-411f-8fe2-63bbaa29ce72",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "calculate_average_recursive",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def is_sorted(lst):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if len(lst) <= 1:\n",
+    "        return True\n",
+    "    else:\n",
+    "        return lst[0] <= lst[1] and is_sorted(lst[1:])\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "id": "0c5c72c6-3237-4f98-ab96-50a1838b833f",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "True"
+      ]
+     },
+     "execution_count": 33,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "is_sorted([1, 2, 3, 4, 5])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "id": "9f18b6b7-d980-4a72-a2a8-3aa201003d21",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_calculate_average_recursive",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert is_sorted([2, 3])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "79eef392-1d3d-46c0-aeee-ac805686e6f1",
+   "metadata": {},
+   "source": [
+    "### Example 9: Check for prime number"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "id": "ac374a08-11c9-47e6-ba11-419549911266",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "is_prime_recursive",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def is_prime_recursive(n, divisor=2):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if n < 2:\n",
+    "        return False\n",
+    "    \n",
+    "    if n == 2:\n",
+    "        return True\n",
+    "    \n",
+    "    if n % divisor == 0:\n",
+    "        return False\n",
+    "    \n",
+    "    if divisor * divisor > n:\n",
+    "        return True\n",
+    "    \n",
+    "    return is_prime_recursive(n, divisor + 1)\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "id": "996fc91f",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "True"
+      ]
+     },
+     "execution_count": 36,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "is_prime_recursive(3)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "id": "5be1051c-3b60-4810-b855-6f8575ad6380",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_is_prime_recursive",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert is_prime_recursive(3) "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5423682d-c31f-4a8d-9a0f-6812de7b1ae3",
+   "metadata": {},
+   "source": [
+    "### Example 10: Count occurrences of a given element in a list"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "id": "cfeb0ad0-ed82-499e-9af3-64923291a0e7",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "count_occurrences",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def count_occurrences(arr, target, index=0):\n",
+    "    ### BEGIN SOLUTION\n",
+    "    if index == len(arr):\n",
+    "        return 0\n",
+    "    \n",
+    "    count = (1 if arr[index] == target else 0)\n",
+    "    \n",
+    "    return count + count_occurrences(arr, target, index + 1)\n",
+    "    ### END SOLUTION"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "id": "49daec07-00b3-412e-ad44-5bafadbd9f36",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "4"
+      ]
+     },
+     "execution_count": 39,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "count_occurrences([1, 2, 3, 4, 2, 2, 5, 6, 2], 2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "id": "14a2eb85-1126-4506-93bb-4bf624d046b6",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "correct_count_occurrences",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert count_occurrences([1, 2, 3, 4, 2, 2, 5, 6, 2], 2) == 4"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "bb1784f5-2426-4661-aa13-dba96743ceb5",
+   "metadata": {},
+   "source": [
+    "# Bonus points"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "7fdcd705-dc0b-4614-8e27-9ba62f8fe442",
+   "metadata": {},
+   "source": [
+    "### Exercise 1: Find the maximum value in a list (iterative)\n",
+    "\n",
+    "Check that an empty lists raises a `ValueError` exception with a `\"The list is empty.\"` message."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 41,
+   "id": "f9334f32-f760-46c0-a649-c82f267aba5b",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "try:\n",
+    "    result = find_maximum_iterative([])\n",
+    "    assert False, \"Exception not raised\"\n",
+    "except ValueError as e:\n",
+    "    assert str(e) == \"The list is empty.\", f\"Expected error message: 'The list is empty.' but got '{str(e)}'\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c121315a-4aaa-4e04-912f-73f56555be56",
+   "metadata": {},
+   "source": [
+    "### Exercise 1: Find the maximum value in a list (recursive)\n",
+    "\n",
+    "Witout using the built-in `max` function"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 48,
+   "id": "153e3f05-7598-4920-bc8d-8943cb75e5a8",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# checks if a function uses another function, eg \"max\"\n",
+    "import inspect\n",
+    "\n",
+    "def calls_builtin_max(func):\n",
+    "    source_code = inspect.getsource(func)\n",
+    "    return 'max(' in source_code\n",
+    "\n",
+    "def my_function(lst):\n",
+    "    return max(lst)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 49,
+   "id": "775b7e32-a5ae-431b-9987-fcd3671fd022",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def find_maximum_recursive_no_max_func(L): \n",
+    "    if not L:\n",
+    "        raise ValueError(\"The list is empty.\")\n",
+    "    \n",
+    "    if len(L) == 1:\n",
+    "        return L[0]\n",
+    "    \n",
+    "    rest_max = find_maximum_recursive(L[1:])\n",
+    "    return L[0] if L[0] > rest_max else rest_max"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 50,
+   "id": "f76ed657-3288-4b36-9175-21168d2eb761",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert not calls_builtin_max(find_maximum_recursive_no_max_func)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "bbe7023a-aabd-489d-bae6-3b71566e22ef",
+   "metadata": {},
+   "source": [
+    "# Additional tests (do not change)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "id": "b8bc657e-d491-4851-aa8c-ac2f2eac0841",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 66,
+   "id": "1c73ad0e-ddc9-483d-85a1-f2a65d04f30b",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert calls_builtin_max(my_function)\n",
+    "assert not calls_builtin_max(find_maximum_iterative)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 72,
+   "id": "8ce960f5-08da-449e-9e6f-dae215bc1b6a",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# generates more examples for a given function\n",
+    "def gen_examples(fnct, n=10):\n",
+    "    return [fnct(i) for i in range(0, n)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "d601b2f3-c33b-4ed2-81be-639ce1ffab76",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1f252530-7817-444c-ae10-d7b3bca87f2d",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0976f7c2-4375-4d76-a6c1-9e729a6c8aeb",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "celltoolbar": "Slideshow",
+  "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
+}