diff --git a/01-data-structures-complexity-exercices.ipynb b/01-data-structures-complexity-exercices.ipynb
index 6a7e9d4b9a1fcf6c02bdecf46e1fdf3e6dc66ad8..b46fdf73fcba8c5fae1186c007f213a51fcfafdb 100644
--- a/01-data-structures-complexity-exercices.ipynb
+++ b/01-data-structures-complexity-exercices.ipynb
@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "markdown",
-   "id": "2bb7e285",
+   "id": "608c95b1",
    "metadata": {},
    "source": [
     "# UE5 Fundamentals of Algorithms\n",
@@ -23,7 +23,7 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "20dd5861",
+   "id": "a934feef",
    "metadata": {},
    "outputs": [],
    "source": [
@@ -33,7 +33,7 @@
   },
   {
    "cell_type": "markdown",
-   "id": "f00472a3",
+   "id": "b498a6a2",
    "metadata": {},
    "source": [
     "---"
@@ -63,6 +63,14 @@
     "---"
    ]
   },
+  {
+   "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": null,
@@ -72,8 +80,7 @@
    },
    "outputs": [],
    "source": [
-    "list_complexities = [\"O(1)\", \"O(log(n))\", \"O(n)\", \"O(n^2)\", \"O(nlog(n))\", \n",
-    "                     \"O(n^3)\", \"O(2^n)\", \"O(n!)\", \"O(n^n)\"]"
+    "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)\"]"
    ]
   },
   {
@@ -229,6 +236,28 @@
     "# YOUR CODE HERE\n",
     "raise NotImplementedError()"
    ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "87b4921b-ef55-4083-b4f1-a3ca5bb7b011",
+   "metadata": {},
+   "source": [
+    "### Additional checks (do not change)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "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": {
diff --git a/02-recursion-exercices.ipynb b/02-recursion-exercices.ipynb
index 5173c4a16bb209c77e0e1d6f6cc742823ac7599b..0ae7ffe7e33d32b044afb7e260e7b1afc2b9b742 100644
--- a/02-recursion-exercices.ipynb
+++ b/02-recursion-exercices.ipynb
@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "markdown",
-   "id": "dadeb4a2",
+   "id": "bca30313",
    "metadata": {},
    "source": [
     "# UE5 Fundamentals of Algorithms\n",
@@ -23,7 +23,7 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "7c45a2a5",
+   "id": "6f6a3d43",
    "metadata": {},
    "outputs": [],
    "source": [
@@ -33,7 +33,7 @@
   },
   {
    "cell_type": "markdown",
-   "id": "f14bc602",
+   "id": "c5b97c1c",
    "metadata": {},
    "source": [
     "---"
@@ -602,9 +602,9 @@
     }
    },
    "source": [
-    "### Example 6: check if annagram\n",
+    "### Example 6: check if a word is an annagram\n",
     "\n",
-    "Écrire une fonction \\texttt{palindrome} qui indique si un mot peut être lu de manière identique dans les deux sens. Donnez la forme itérative et récursive.\n"
+    "Check if a word can be read backwards."
    ]
   },
   {
@@ -771,7 +771,7 @@
     "deletable": false,
     "nbgrader": {
      "cell_type": "code",
-     "checksum": "ccdab0e0b54c6ff4e1835b4a57a4ac72",
+     "checksum": "3dfcf16aa7e5f7e1f4e46a799e964624",
      "grade": false,
      "grade_id": "calculate_average_recursive",
      "locked": false,
@@ -785,7 +785,7 @@
    "source": [
     "def calculate_average_recursive(lst, index=0):\n",
     "    # YOUR CODE HERE\n",
-    "    raise NotImplementedError()\n"
+    "    raise NotImplementedError()"
    ]
   },
   {
diff --git a/03-lists-search-sort-exercises.ipynb b/03-lists-search-sort-exercises.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..3d5c261bef217345cb2f9c87138028f365855172
--- /dev/null
+++ b/03-lists-search-sort-exercises.ipynb
@@ -0,0 +1,631 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "d8056b8c",
+   "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": "9c5894f5",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ID = \"\"\n",
+    "COLLABORATORS_ID = []"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "838b13ee",
+   "metadata": {},
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e58599e3-9ab7-4d43-bb22-aeccade424ce",
+   "metadata": {},
+   "source": [
+    "# Lists, search, sort"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "691b3c38-0e83-4bb2-ac90-ef76d2dd9a7a",
+   "metadata": {},
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "9d813205-b709-42ab-b414-6f3fc947022a",
+   "metadata": {},
+   "source": [
+    "## Exerccise 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, ..)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f3b233ec-7077-479d-9c04-f1a4c35f3111",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "2791444cbfd4f0f74f1ce7f2a330ecec",
+     "grade": false,
+     "grade_id": "search_list",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def search_list(L, target):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "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": [],
+   "source": [
+    "search_list([1, 2, 2], 3)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "423d2637-8bd6-4e8f-95ff-2765dae5bce7",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert search_list([1, 2, 3, 4, 5], 3) == 2\n",
+    "assert search_list([1, 2, 3, 4, 5], 6) == -1\n",
+    "assert search_list([1, 2, 3, 4, 5, 6], 6) == -1\n",
+    "assert search_list([], 42) == -1\n",
+    "assert search_list([7, 2, 3, 4, 5], 7) == 0\n",
+    "assert search_list([1, 2, 3, 4, 5, 6], 6) == -1"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "6d8dc6cd-aad0-42a9-b768-6a1a5289e354",
+   "metadata": {},
+   "source": [
+    "## Exerccise 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"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "8271ff47-efb4-48a0-ac4c-bba6ede7e578",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "d36956e43a1d9a594625212c58f4560a",
+     "grade": false,
+     "grade_id": "sort_list_of_lists_by_nth_element",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def sort_list_of_lists_by_nth_element(list_of_lists, N):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()\n",
+    "# Example usage:\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "4577bd24-9e50-4172-8246-d1bccfa21618",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "list_of_lists = [[3, 5, 1], [1, 2, 9], [7, 4, 6], [2, 8, 3]]\n",
+    "sorted_list = sort_list_of_lists_by_nth_element(list_of_lists, 2)\n",
+    "print(sorted_list)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ed3cdeed-07fa-461f-b7ae-210e1605ca76",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "135ef51ad6ac5ce059a50fccc46a99e4",
+     "grade": true,
+     "grade_id": "correct_sort_list_of_lists_by_nth_element",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "list1 = [[3, 5, 1], [1, 2, 9], [7, 4, 6], [2, 8, 3]]\n",
+    "sorted_list1 = sort_list_of_lists_by_nth_element(list1, 2)\n",
+    "assert sorted_list1 == [[3, 5, 1], [2, 8, 3], [7, 4, 6], [1, 2, 9]], \"Test Case 1 Failed\"\n",
+    "\n",
+    "list2 = [[9, 5, 7], [3, 6, 1], [0, 2, 4], [8, 1, 5]]\n",
+    "sorted_list2 = sort_list_of_lists_by_nth_element(list2, 0)\n",
+    "assert sorted_list2 == [[0, 2, 4], [3, 6, 1], [8, 1, 5], [9, 5, 7]], \"Test Case 2 Failed\"\n",
+    "\n",
+    "list3 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]\n",
+    "sorted_list3 = sort_list_of_lists_by_nth_element(list3, 1)\n",
+    "assert sorted_list3 == [[1, 2, 3], [4, 5, 6], [7, 8, 9]], \"Test Case 3 Failed\"\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0bbda1ba-a5e7-4a1d-a742-84d0215b1e24",
+   "metadata": {},
+   "source": [
+    "## Exerccise 3: Access a list element"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "2d6a6f11-d24b-4f0e-a7d2-298243e35c4d",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "df3e8c605c7e96af2267865e04990e5a",
+     "grade": false,
+     "grade_id": "cell-1ab0b636df63501a",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def access_dict_element(L, index, key):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ea0883dc-d08c-40ea-9e0b-4f0a3abc517f",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "example_list = [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}]\n",
+    "result = access_dict_element(example_list, 0, 'name')\n",
+    "print(result) "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "88ae441e-58b1-4d6c-a639-530919658d03",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "c77eefc574735feb146d00c86553b601",
+     "grade": true,
+     "grade_id": "correct_access_dict_element",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "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"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "98405b12-ad61-4007-8c9f-6955d238df41",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "## Exerccise 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`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e079e47b-2f9e-42d1-a78b-56c92ad84d63",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def is_odd(x):\n",
+    "    return x % 2 != 0"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "536734bd-d4cc-4f83-8042-3c0e774c4034",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "46e9b2d0caa1061f9d00cf2859441701",
+     "grade": false,
+     "grade_id": "remove_elements",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def remove_elements(lst, condition):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "a65bb6f1-b7c7-4156-ba8b-9b72a25616f3",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
+    "remove_elements(my_list, is_odd)\n",
+    "print(my_list)  # Should print [2, 4, 6, 8]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "254155dc-b271-4881-ac65-5a11d13990ea",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "7d18e8b7e4619abfc3e78fb2f2801892",
+     "grade": true,
+     "grade_id": "correct_remove_elements",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "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",
+    "\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",
+    "\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",
+    "remove_elements(test_list_3, custom_condition)\n",
+    "assert test_list_3 == [1, 2, 4, 5, 7, 8]\n",
+    "\n",
+    "test_list_4 = [42, 99, 101]\n",
+    "remove_elements(test_list_4, lambda x: True)\n",
+    "assert test_list_4 == [], \"Remove all elements\"\n",
+    "\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\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d75dba4b-ac22-4f2c-9a6c-cf333b1ec5e8",
+   "metadata": {},
+   "source": [
+    "## Exercise 5: Sort a dictionnary by values\n",
+    "\n",
+    "List a dictionnary (not a list!) by value."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "556be9d8-b8c3-4f1d-bcb1-8f099968af9d",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "6bfb51c12c41947733534307eb1cf5c4",
+     "grade": false,
+     "grade_id": "sort_dict_by_values",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def sort_dict_by_values(input_dict):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()\n",
+    "    return sorted_dict"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "3c32c4ee-56f5-46b5-a8b6-b740e6d5fef5",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "test_dict3 = {'c': 3, 'b': 2, 'a': 1}\n",
+    "sorted_dict3 = sort_dict_by_values(test_dict3)\n",
+    "assert sorted_dict3 == {'a': 1, 'b': 2, 'c': 3}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "532e5225-a2d8-4c10-a036-1efde9acc5fd",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "8a4001090e87ce0c5d773621ed0a3ea9",
+     "grade": true,
+     "grade_id": "correct_sort_dict_by_values",
+     "locked": true,
+     "points": 0,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "test_dict = {'banana': 3, 'apple': 1, 'cherry': 2}\n",
+    "sorted_dict = sort_dict_by_values(test_dict)\n",
+    "assert sorted_dict == {'apple': 1, 'cherry': 2, 'banana': 3}\n",
+    "\n",
+    "test_dict2 = {'zebra': 42, 'lion': 7, 'elephant': 15, 'giraffe': 23}\n",
+    "sorted_dict2 = sort_dict_by_values(test_dict2)\n",
+    "assert sorted_dict2 == {'lion': 7, 'elephant': 15, 'giraffe': 23, 'zebra': 42}\n",
+    "\n",
+    "test_dict3 = {'one': 3, 'two': 3, 'three': 3, 'four': 3}\n",
+    "sorted_dict3 = sort_dict_by_values(test_dict3)\n",
+    "assert sorted_dict3 == {'one': 3, 'two': 3, 'three': 3, 'four': 3}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fef2ad7f-55ef-43f2-991d-5067bb085eb6",
+   "metadata": {},
+   "source": [
+    "## Exercise 6: insertion sort\n",
+    "\n",
+    "Implement the `insertion sort` that operates as follows:\n",
+    "\n",
+    "- Start with an unsorted list.\n",
+    "- Iterate through each element in the list.\n",
+    "- For each element, compare it with the elements to its left in the list.\n",
+    "- Move elements to the right until you find the correct position for the current element.\n",
+    "- Insert the current element into its proper place in the sorted portion of the list.\n",
+    "- Repeat this process for all elements, gradually building a sorted list from left to right."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "51a86852-f8e2-4c05-8053-13fdf2a4832b",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "84421b7199764b6fe3485117b23fb0a1",
+     "grade": false,
+     "grade_id": "insertion_sort",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def insertion_sort(arr):\n",
+    "    # YOUR CODE HERE\n",
+    "    raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "fbfa74f1-4675-452f-897b-21b0c7025f81",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "print(insertion_sort([2, 1, 3, 4, 5]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "266e89e0-4b59-441f-bb67-69ad4e35e2a9",
+   "metadata": {
+    "deletable": false,
+    "editable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "dc6fc6f16aa2c62a5e1e39382106b0bf",
+     "grade": true,
+     "grade_id": "correct_insertion_sort",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# Test case 2: Already sorted list\n",
+    "arr = [1, 2, 3, 4, 5]\n",
+    "assert insertion_sort(arr) == arr\n",
+    "\n",
+    "# Test case 3: Reverse sorted list\n",
+    "arr = [5, 4, 3, 2, 1]\n",
+    "assert insertion_sort(arr) == [1, 2, 3, 4, 5]\n",
+    "\n",
+    "# Test case 4: Random order list\n",
+    "arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]\n",
+    "assert insertion_sort(arr) == [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "ab78dd44-bb6a-451d-8642-223639d31bf9",
+   "metadata": {},
+   "source": [
+    "## Bonus\n",
+    "\n",
+    "You may get bonus points for the following answers:\n",
+    "\n",
+    "- add exceptions https://docs.python.org/3/library/exceptions.html\n",
+    "- add more test cases"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "74d4e305-f42d-4813-9a77-072989bb7e62",
+   "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/03-lists-search-sort-slides.pdf b/03-lists-search-sort-slides.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..f8b682986e73fda8cb61e2b475265c0d1d112b68
Binary files /dev/null and b/03-lists-search-sort-slides.pdf differ
diff --git a/03-lists-search-sort.ipynb b/03-lists-search-sort.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..380986258b08a8025f158a66146ef2c90535ffbc
--- /dev/null
+++ b/03-lists-search-sort.ipynb
@@ -0,0 +1,804 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "bec049ad",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "cell-6892cebeacb58715",
+     "locked": true,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    },
+    "slideshow": {
+     "slide_type": "slide"
+    }
+   },
+   "source": [
+    "# UE5 Fundamentals of Algorithms\n",
+    "## Lecture 3: Lists, search, sort\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>\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",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Outline\n",
+    "- Definition and examples of lists\n",
+    "- Manipulate\n",
+    "- Search\n",
+    "- Sort\n",
+    "- Iterate\n",
+    "- Filter/Map"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "ab21085a",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## What is a list?\n",
+    "\n",
+    "> A **list** is a linear data structure \n",
+    "\n",
+    "- A sequence of elements\n",
+    "- Each element has a position (index)\n",
+    "- The order of the elements is important\n",
+    "- The elements can be of any type\n",
+    "\n",
+    "Examples of lists:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "4fcb6bdb",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "numbers_list = [1, 2, 3, 4, 5]\n",
+    "strings_list = [\"apple\", \"banana\", \"cherry\", \"date\"]\n",
+    "mixed_list = [1, \"apple\", 3.14, True]\n",
+    "nested_list = [[1, 2, 3], [\"a\", \"b\", \"c\"], [True, False]]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "bb445f5c",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### List operations\n",
+    "\n",
+    "- **Access** an element at a given position\n",
+    "- **Insert** an element at a given position\n",
+    "- **Remove** an element at a given position\n",
+    "- **Search** an element\n",
+    "- **Sort** the list\n",
+    "- **Reverse** the list"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "cc05f88e",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Access\n",
+    "\n",
+    "> Return a value"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "33da6137",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "L = [1, 2, 3]\n",
+    "\n",
+    "for val in tab:\n",
+    "    print(val)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "990e937d",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### Example: is a list ordered?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "05a3d562",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def estordonnee(liste):\n",
+    "\n",
+    "    for i in range(len(liste) - 1):\n",
+    "        if liste[i + 1] < liste[i]:\n",
+    "            return False\n",
+    "    return True\n",
+    "\n",
+    "print(estordonnee([1,2,3,4]))\n",
+    "print(estordonnee([1,2,3,4,1]))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "3e822b32",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Insert\n",
+    "\n",
+    "> Add elements in the list (regardless the index)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5aad3402",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from time import time\n",
+    "\n",
+    "def compute_average(n):\n",
+    "    data = []\n",
+    "    start = time()\n",
+    "    for k in range(n):\n",
+    "        data.append(None)\n",
+    "    end = time()\n",
+    "    return (end - start) / n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "37c3b4a7",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "compute_average(20)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "9c4be228",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "-"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "my_list = [1, 2, 3, 4, 5]\n",
+    "insert_elements = [99, 100]\n",
+    "my_list = my_list[:2] + insert_elements + my_list[2:]\n",
+    "print(my_list)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5d95ee75",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "# Search\n",
+    "\n",
+    "> Given a list of elements, find the position of a given element\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "8a5dd42f",
+   "metadata": {
+    "nbgrader": {
+     "grade": false,
+     "grade_id": "cell-387c098b188d4707",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    }
+   },
+   "outputs": [],
+   "source": [
+    "def search_element_in_list(element, list):\n",
+    "    for i in list:\n",
+    "        if i == element:\n",
+    "            return True\n",
+    "    return False"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "a3e4ed1f",
+   "metadata": {
+    "nbgrader": {
+     "grade": true,
+     "grade_id": "cell-d5f44386312e81c0",
+     "locked": true,
+     "points": 1,
+     "schema_version": 3,
+     "solution": false,
+     "task": false
+    }
+   },
+   "outputs": [],
+   "source": [
+    "L = [1, 2, 3, 4, 5]\n",
+    "element_to_find = 3\n",
+    "\n",
+    "try:\n",
+    "    index = L.index(element_to_find)\n",
+    "    print(f\"{element_to_find} found at index {index}.\")\n",
+    "except ValueError:\n",
+    "    print(f\"{element_to_find} is not in the list.\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "52399db0",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### Example: Binary search (pseudo code)\n",
+    "\n",
+    "- **Input**: A sorted list (array) and a target value to find.\n",
+    "- **Initialization**:\n",
+    "  - Set a pointer `left` to the beginning of the list (index 0).\n",
+    "  - Set a pointer `right` to the end of the list (index equal to the length of the list minus one).\n",
+    "- **Search**:\n",
+    "  - While `left` is less than or equal to `right`:\n",
+    "    - Calculate the middle index as `mid` by adding `left` and `right` and then dividing by 2.\n",
+    "    - Check if the element at index `mid` in the list is equal to the target value:\n",
+    "      - If it is, you've found the target, so return `mid`.\n",
+    "    - If the element at index `mid` is less than the target:\n",
+    "      - Update `left` to `mid + 1` to search in the right half of the list.\n",
+    "    - If the element at index `mid` is greater than the target:\n",
+    "      - Update `right` to `mid - 1` to search in the left half of the list.\n",
+    "- **Result**:\n",
+    "  - If you've gone through the entire loop and haven't found the target, return -1 to indicate that the target is not in the list."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "id": "0d5eeb2c",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "outputs": [],
+   "source": [
+    "### Example: Binary search (pseudo code)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "id": "1197437b",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "-"
+    }
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Element 5 found at index 4.\n"
+     ]
+    }
+   ],
+   "source": [
+    "def binary_search(arr, target):\n",
+    "    left, right = 0, len(arr) - 1\n",
+    "\n",
+    "    while left <= right:\n",
+    "        mid = (left + right) // 2  # Calculate the middle index\n",
+    "\n",
+    "        if arr[mid] == target:\n",
+    "            return mid  # Element found, return its index\n",
+    "        elif arr[mid] < target:\n",
+    "            left = mid + 1  # Search the right half\n",
+    "        else:\n",
+    "            right = mid - 1  # Search the left half\n",
+    "\n",
+    "    return -1  # Element not found\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",
+    "\n",
+    "if result != -1:\n",
+    "    print(f\"Element {target_element} found at index {result}.\")\n",
+    "else:\n",
+    "    print(f\"Element {target_element} not found in the list.\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "08843d8f",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "# Sort\n",
+    "\n",
+    "> Given a list of elements, sort the elements according to a given order\n",
+    "\n",
+    "- **Ascending** order\n",
+    "- **Descending** order\n",
+    "- **Alphabetical** order\n",
+    "- **Reverse** order\n",
+    "- **Custom** order\n",
+    "\n",
+    "NB: Sort is more complex and will be studied later on."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "879f8d7c",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "### All the ways to sort a list "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "dead2e0b",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]\n",
+    "sorted_list = sorted(my_list)\n",
+    "print(sorted_list)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "01e4d112",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]\n",
+    "sorted_numbers = sorted(numbers)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e2c9277a",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]\n",
+    "numbers.sort(reverse=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "26d6dad8",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]\n",
+    "numbers.sort()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "34975051",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "words = ['apple', 'banana', 'cherry', 'date']\n",
+    "sorted_words = sorted(words, key=len)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "ee60b8ff",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Enumerators\n",
+    "\n",
+    "> Enables to turn a list into a list of index + value\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "id": "c1bdb416",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0 1\n",
+      "1 2\n",
+      "2 3\n",
+      "0 1 A\n",
+      "1 2 B\n",
+      "2 3 C\n"
+     ]
+    }
+   ],
+   "source": [
+    "a = [1, 2, 3]\n",
+    "b = [\"A\", \"B\", \"C\"]\n",
+    "\n",
+    "for index, value in enumerate(L):\n",
+    "    print(index, value)\n",
+    "    \n",
+    "for i, (x, y) in enumerate(zip(a, b)):\n",
+    "    print(i, x, y)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "15eebc0d",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1\n",
+      "2\n",
+      "3\n"
+     ]
+    }
+   ],
+   "source": [
+    "iterable = [1, 2, 3]\n",
+    "iterator = iter(iterable)\n",
+    "\n",
+    "try:\n",
+    "    while True:\n",
+    "        item = next(iterator)\n",
+    "        print(item)\n",
+    "except StopIteration:\n",
+    "    pass"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e97201fc",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Iterators"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "bc13a581",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "iterable = [1, 2, 3, 4, 5]\n",
+    "iterator = iter(iterable)\n",
+    "\n",
+    "try:\n",
+    "    while True:\n",
+    "        item = next(iterator)\n",
+    "        print(item)\n",
+    "except StopIteration:\n",
+    "    pass"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "8297afc9",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Generators"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "269c01b9",
+   "metadata": {},
+   "source": [
+    "Using generators"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "289eb2ba",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1\n",
+      "2\n",
+      "3\n"
+     ]
+    }
+   ],
+   "source": [
+    "def my_iterator():\n",
+    "    data = [1, 2, 3]\n",
+    "    for item in data:\n",
+    "        yield item\n",
+    "\n",
+    "for item in my_iterator():\n",
+    "    print(item)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0a882d1d",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "source": [
+    "## Linked list\n",
+    "\n",
+    "> A **_linked_ list** is a sequence of values (or objects) called *nodes* that are connected to each other in order to facilitate their storage and retrieval.\n",
+    "\n",
+    "\n",
+    "- The first node is called the head, the last node is the tail, and it points to `null`.\n",
+    "\n",
+    "- This structure allows for a flexible approach to manipulating objects: increasing their number, order, etc.\n",
+    "\n",
+    "- Especially allows for **dynamic memory allocation**, whereas an array needs to allocate all the space before being filled.\n",
+    "\n",
+    "- 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,
+   "id": "53534019",
+   "metadata": {
+    "slideshow": {
+     "slide_type": "subslide"
+    }
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 -> 2 -> 3 -> None\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Initialize an empty linked list\n",
+    "linked_list = None\n",
+    "\n",
+    "# Function to append data to the linked list\n",
+    "def append(data):\n",
+    "    global linked_list\n",
+    "    if linked_list is None:\n",
+    "        linked_list = {\"data\": data, \"next\": None}\n",
+    "    else:\n",
+    "        current = linked_list\n",
+    "        while current[\"next\"]:\n",
+    "            current = current[\"next\"]\n",
+    "        current[\"next\"] = {\"data\": data, \"next\": None}\n",
+    "\n",
+    "# Function to traverse and print the linked list\n",
+    "def traverse():\n",
+    "    current = linked_list\n",
+    "    while current:\n",
+    "        print(current[\"data\"], end=\" -> \")\n",
+    "        current = current[\"next\"]\n",
+    "    print(\"None\")\n",
+    "\n",
+    "# Append some data to the linked list\n",
+    "append(1)\n",
+    "append(2)\n",
+    "append(3)\n",
+    "\n",
+    "# Print the linked list\n",
+    "traverse()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5c865215",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "id": "28564ab2",
+   "metadata": {},
+   "source": [
+    "## Filter\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "id": "3012f2e3",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[6, 7, 8, 9]"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "x = range(10)\n",
+    "list(x)\n",
+    "list(filter(lambda x : x > 5, x))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5c0860da",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "## Map"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "435094a4",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "list(map(lambda x : x * x, x))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5575cf08",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "fb30b1ce",
+   "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
+}
diff --git a/README.md b/README.md
index 31fb64acfed0d101c17ad8b7ffa17ec7d9126d6e..822085d8e2c4665262f1ce85bd5dd7e7dad2fc5f 100644
--- a/README.md
+++ b/README.md
@@ -13,33 +13,45 @@ Instructor: [Romain Vuillemot](romain.vuillemot@ec-lyon.fr)
 
 ## Outline
 
-### Lecture 1 - **Data structures and complexity** | [notebook](01-introduction.ipynb) | [slides](01-introduction-slides.pdf)
+### Lecture 1 - **Data structures and complexity** | [notebook](01-introduction.ipynb) | [slides](01-introduction-slides.pdf) | [exercices](01-introduction-exercices.ipynb)
 
 📖 [Python for Everybody](pdf/pythonlearn.pdf) chapter 9 (dictionnaries), chapter 10 (tuples)
 
 ### Lecture 2 - **Recursion** | [notebook](02-recursion.ipynb) | [slides](02-recursion-slides.pdf) | [exercices](02-recursion-exercices.ipynb)
 
-📖 [Think Python](pdf/thinkpython2.pdf) chapter 5 (Conditionals and recursion) and [Real Python](https://realpython.com/python-recursion/).
+📖 [Think Python](pdf/thinkpython2.pdf) chapter 5 (Conditionals and recursion) and Real Python [recursion](https://realpython.com/python-recursion/).
 
-### Lecture 3 - **Lists, search, sort** 
+### Lecture 3 - **Lists, search, sort** | [notebook](03-lists-search-sort.ipynb) | [slides](03-lists-search-sort-slides.pdf) | [exercices](03-lists-search-sort-exercises.ipynb)
 
-📖 [Think Python](pdf/thinkpython2.pdf) chapter 11 (lists), chapter 12 (tuples), [Python for Everybody](pdf/pythonlearn.pdf) chapter 8 (lists) and [Real Python](https://realpython.com/python-list/).
+📖 [Think Python](pdf/thinkpython2.pdf) chapter 11 (lists), chapter 12 (tuples), [Python for Everybody](pdf/pythonlearn.pdf) chapter 8 (lists) and Real Python [lists](https://realpython.com/python-list/) and [sorts](https://realpython.com/sorting-algorithms-python/).
 
-📝 Assignment 1 - Analyzing a Simple Dataset
+--- 
 
-### Lecture 4 - **Divide and conquer and greedy algorithms** 
+📝 Assignment 1 - Analyzing a simple dataset
 
-### Lecture 5 - **Dynamic programming** 
+---
 
- 📝Assignment 2 - Solving a problem with dynamic programming
+### Lecture 4 - **Programming strategies** 
+
+📖 [Divide & conquer](https://en.wikibooks.org/wiki/Algorithms/Divide_and_Conquer), [dynamic programing](https://en.wikibooks.org/wiki/Algorithms/Dynamic_Programming) and [greedy algorithms](https://en.wikibooks.org/wiki/Algorithms/Greedy_Algorithms)
+
+### Lecture 5 - **Trees** 
+
+📖 [Problem Solving with Algorithms](pdf/problemsolving.pdf) chapter 6 (trees and tree algorithms)
+
+---
+
+📝Assignment 2 - Solving a problem with dynamic programming
+
+---
 
 Next topics:
 
-1. **Advanced sorting**
+1. **Stacks and queues**
 
-2. **Hashing**
+2. **Advanced data structures**
 
-3. **Trees**
+3. **Hashing**
 
 4. **Trees and their representation**
 
@@ -47,13 +59,16 @@ Next topics:
 
 6. **Binary and n-trees**
 
-7.  **Graphs**
+7. **Graphs**
 
-8.  **Graphs algorithms**
+8. **Graphs algorithms**
 
-9.   **Graphs shortest path algorithm**
+9. **Graphs shortest path algorithm**
 
-## Books
+## Books and ressources
 
 - [Think Python](pdf/thinkpython2.pdf), 2nd edition, by Allen B. Downey
-- [Python for Everybody](pdf/pythonlearn.pdf), by Charles Severance
\ No newline at end of file
+- [Python for Everybody](pdf/pythonlearn.pdf), by Charles Severance
+- [Problem Solving with Algorithms and Data Structures using Python](pdf/problemsolving.pdf), by Brad Miller and David Ranum
+- https://en.wikibooks.org/wiki/Algorithms/
+- List of [computer science books](https://freecomputerbooks.com/compscAlgorithmBooks.html)
\ No newline at end of file
diff --git a/pdf/Dsa.pdf b/pdf/Dsa.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..abe92653999f42e44c1388f7216d6d943112d103
Binary files /dev/null and b/pdf/Dsa.pdf differ
diff --git a/pdf/Python_Algorithms_Data_Structures.pdf b/pdf/Python_Algorithms_Data_Structures.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..60ca2094c0549d3d321498938108940e2ebb9313
Binary files /dev/null and b/pdf/Python_Algorithms_Data_Structures.pdf differ
diff --git a/pdf/problemsolving.pdf b/pdf/problemsolving.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..e3bddf21a98610071a3de443c3906166446de234
Binary files /dev/null and b/pdf/problemsolving.pdf differ