{"id":21836923,"url":"https://github.com/waldohidalgo/coding-interview-prep","last_synced_at":"2026-05-08T16:53:40.844Z","repository":{"id":249457817,"uuid":"831567690","full_name":"waldohidalgo/coding-interview-prep","owner":"waldohidalgo","description":"Coding Interview Prep: repositorio con mis soluciones a los problemas de Algorithms y Data Structures presentes en la página de preparación de entrevistas de Freecodecamp","archived":false,"fork":false,"pushed_at":"2024-07-25T22:35:02.000Z","size":191,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-21T15:03:41.698Z","etag":null,"topics":["algorithms","algorithms-and-data-structures","binary-search-tree","bubble-sort","doubly-linked-list","freecodecamp-challenge","freecodecamp-project","hashtable","insertion-sort","linked-list","queue","quicksort","selection-sort","stack"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/waldohidalgo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-21T00:21:30.000Z","updated_at":"2024-07-25T22:35:05.000Z","dependencies_parsed_at":"2024-07-21T01:43:11.653Z","dependency_job_id":"65420f34-658c-45bf-909f-c7d40aa5d1ac","html_url":"https://github.com/waldohidalgo/coding-interview-prep","commit_stats":null,"previous_names":["waldohidalgo/coding-interview-prep"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/waldohidalgo/coding-interview-prep","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fcoding-interview-prep","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fcoding-interview-prep/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fcoding-interview-prep/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fcoding-interview-prep/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/waldohidalgo","download_url":"https://codeload.github.com/waldohidalgo/coding-interview-prep/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/waldohidalgo%2Fcoding-interview-prep/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32789370,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"ssl_error","status_checked_at":"2026-05-08T08:22:45.650Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithms","algorithms-and-data-structures","binary-search-tree","bubble-sort","doubly-linked-list","freecodecamp-challenge","freecodecamp-project","hashtable","insertion-sort","linked-list","queue","quicksort","selection-sort","stack"],"created_at":"2024-11-27T20:43:41.941Z","updated_at":"2026-05-08T16:53:40.816Z","avatar_url":"https://github.com/waldohidalgo.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Coding Interview Prep\n\nRepositorio con mis soluciones a los problemas presentes en la página [Coding Interview Prep\n](https://www.freecodecamp.org/learn/coding-interview-prep/) de freecodecamp. Los problemas se dividen en dos temas: **Algorithms** y **Data Structures** resueltos utilizando javascript.\n\n## Tabla de Contenidos\n\n- [Coding Interview Prep](#coding-interview-prep)\n  - [Tabla de Contenidos](#tabla-de-contenidos)\n  - [Algorithms](#algorithms)\n    - [100% Completed](#100-completed)\n    - [Lista de Algoritmos](#lista-de-algoritmos)\n      - [1-Find the Symmetric Difference](#1-find-the-symmetric-difference)\n      - [2-Inventory Update](#2-inventory-update)\n      - [3-No Repeats Please](#3-no-repeats-please)\n      - [4-Pairwise](#4-pairwise)\n      - [5-Implement Bubble Sort](#5-implement-bubble-sort)\n      - [6-Implement Selection Sort](#6-implement-selection-sort)\n      - [7-Implement insertion Sort](#7-implement-insertion-sort)\n      - [8-Implement Quick Sort](#8-implement-quick-sort)\n      - [9-Implement Merge Sort](#9-implement-merge-sort)\n      - [10-Implement Binary Search](#10-implement-binary-search)\n  - [Data Structures](#data-structures)\n    - [100% Completed](#100-completed-1)\n    - [Lista de Data Structures](#lista-de-data-structures)\n      - [1-Stack](#1-stack)\n      - [2-Queue](#2-queue)\n      - [3-Priority Queue](#3-priority-queue)\n      - [4-Circular Queue](#4-circular-queue)\n      - [5-Set](#5-set)\n      - [6-Map](#6-map)\n      - [7-Tabla Hash](#7-tabla-hash)\n      - [8- Linked List](#8--linked-list)\n      - [9-Doubly Linked List](#9-doubly-linked-list)\n      - [10-Binary Search Tree](#10-binary-search-tree)\n        - [10.1-Add a new element to a Binary Search Tree](#101-add-a-new-element-to-a-binary-search-tree)\n        - [10.2-Find the Minimum and Maximum Value in a Binary Search Tree](#102-find-the-minimum-and-maximum-value-in-a-binary-search-tree)\n        - [10.3-Check if an Element is Present in a Binary Search Tree](#103-check-if-an-element-is-present-in-a-binary-search-tree)\n        - [10.4-Check if Tree is Binary Search Tree](#104-check-if-tree-is-binary-search-tree)\n        - [10.5-Find the Minimum and Maximum Height of a Binary Search Tree](#105-find-the-minimum-and-maximum-height-of-a-binary-search-tree)\n        - [10.6-Use Depth First Search in a Binary Search Tree](#106-use-depth-first-search-in-a-binary-search-tree)\n        - [10.7-Use Breadth First Search in a Binary Search Tree](#107-use-breadth-first-search-in-a-binary-search-tree)\n        - [10.8-Delete a Leaf Node in a Binary Search Tree](#108-delete-a-leaf-node-in-a-binary-search-tree)\n        - [10.9-Delete a Node with One Child in a Binary Search Tree](#109-delete-a-node-with-one-child-in-a-binary-search-tree)\n        - [10.10-Delete a Node with Two Children in a Binary Search Tree](#1010-delete-a-node-with-two-children-in-a-binary-search-tree)\n        - [10.11-Invert a Binary Tree](#1011-invert-a-binary-tree)\n      - [11-Create a Trie Search Tree](#11-create-a-trie-search-tree)\n      - [12-Binary Heap](#12-binary-heap)\n        - [12.1-Insert an Element into a Max Heap](#121-insert-an-element-into-a-max-heap)\n        - [12.2-Remove an Element from a Max Heap](#122-remove-an-element-from-a-max-heap)\n        - [12.3-Implement Heap Sort with a Min Heap](#123-implement-heap-sort-with-a-min-heap)\n      - [13-Graphs](#13-graphs)\n        - [13.1-Adjacency List](#131-adjacency-list)\n        - [13.2-Adjacency Matrix](#132-adjacency-matrix)\n        - [13.3-Incidence Matrix](#133-incidence-matrix)\n        - [13.4-Breadth-First Search](#134-breadth-first-search)\n        - [13.5-Depth-First Search](#135-depth-first-search)\n\n## Algorithms\n\n### 100% Completed\n\n![100% Completed Screenshot](./Algorithms/completed.webp)\n\n### Lista de Algoritmos\n\n#### 1-Find the Symmetric Difference\n\n```js\nfunction sym(...args) {\n  const sets = args.map((set) =\u003e new Set(set));\n\n  const setSym = sets.reduce((set, set2) =\u003e {\n    let diff = new Set();\n\n    for (let item of set) {\n      if (!set2.has(item)) {\n        diff.add(item);\n      }\n    }\n    for (let item of set2) {\n      if (!set.has(item) \u0026\u0026 !diff.has(item)) {\n        diff.add(item);\n      }\n    }\n\n    return diff;\n  });\n  return [...setSym].sort((a, b) =\u003e a - b);\n}\n```\n\n#### 2-Inventory Update\n\n```js\nfunction updateInventory(curInv, newInv) {\n  return curInv\n    .concat(newInv)\n    .reduce((acc, arrItem) =\u003e {\n      const [qty, item] = arrItem;\n      const itemIndex = acc.findIndex((arrItem) =\u003e arrItem[1] === item);\n      if (itemIndex \u003e -1) {\n        acc[itemIndex][0] += qty;\n      } else {\n        acc.push(arrItem);\n      }\n\n      return acc;\n    }, [])\n    .sort((a, b) =\u003e a[1].localeCompare(b[1]));\n}\n```\n\n#### 3-No Repeats Please\n\n```js\nfunction permAlone(str) {\n  function noRepeatPlease(str) {\n    if (str.length === 1) {\n      return str;\n    }\n\n    if (str.length === 2) {\n      if (str[0] === str[1]) {\n        return [\"\"];\n      }\n      return [`${str[0]}${str[1]}`, `${str[1]}${str[0]}`];\n    }\n    let arrayFinal = [];\n\n    for (let i = 0; i \u003c str.length; i++) {\n      const newStr = str.slice(0, i) + str.slice(i + 1);\n      const array = noRepeatPlease(newStr);\n\n      const newArray = [];\n\n      for (let j = 0; j \u003c array.length; j++) {\n        if (str[i] !== array[j][0] \u0026\u0026 array[j] !== \"\") {\n          newArray.push(str[i] + array[j]);\n        }\n      }\n\n      arrayFinal = arrayFinal.concat(newArray);\n    }\n\n    return arrayFinal;\n  }\n\n  return noRepeatPlease(str).length;\n}\n```\n\n#### 4-Pairwise\n\n```js\nfunction pairwise(arr, arg) {\n  const newArr = arr.map((e, i) =\u003e ({ [i]: e }));\n  const pares = [];\n  const indicesYaConsiderados = [];\n  for (let i = 0; i \u003c newArr.length; i++) {\n    for (let j = i + 1; j \u003c newArr.length; j++) {\n      if (\n        !indicesYaConsiderados.includes(j) \u0026\u0026\n        !indicesYaConsiderados.includes(i)\n      ) {\n        if (newArr[i][i] + newArr[j][j] === arg) {\n          pares.push([Object.keys(newArr[i])[0], Object.keys(newArr[j])[0]]);\n          indicesYaConsiderados.push(j);\n          indicesYaConsiderados.push(i);\n        }\n      }\n    }\n  }\n\n  return pares.reduce((acc, elem) =\u003e acc + +elem[0] + +elem[1], 0);\n}\n```\n\n#### 5-Implement Bubble Sort\n\n```js\nfunction bubbleSort(array) {\n  // Only change code below this line\n\n  if (array.length \u003c= 1) return array;\n\n  let isOrdered = false;\n  while (!isOrdered) {\n    for (let i = 0; i \u003c array.length - 1; i++) {\n      if (array[i] \u003e array[i + 1]) {\n        [array[i], array[i + 1]] = [array[i + 1], array[i]];\n        break;\n      }\n      if (i === array.length - 2) {\n        isOrdered = true;\n      }\n    }\n  }\n  return array;\n  // Only change code above this line\n}\n```\n\nSabiendo que en cada recorrido se posiciona el mayor valor al final del array entonces se disminuye el final en cada recorrido lo que permite realizar la siguiente implementación alternativa:\n\n```js\nfunction bubbleSort2(arr) {\n  for (let i = arr.length - 1; i \u003e 0; i--) {\n    for (let j = 0; j \u003c i; j++) {\n      if (arr[j] \u003e arr[j + 1]) {\n        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];\n      }\n    }\n  }\n  return arr;\n}\n```\n\n#### 6-Implement Selection Sort\n\n```js\nfunction selectionSort(array) {\n  // Only change code below this line\n\n  for (let i = 0; i \u003c array.length - 1; i++) {\n    const subArr = array.slice(i);\n    const minValue = Math.min(...subArr);\n    const minIndex = subArr.indexOf(minValue) + i;\n    if (minIndex === i) {\n      continue;\n    } else {\n      [array[i], array[minIndex]] = [array[minIndex], array[i]];\n    }\n  }\n  return array;\n  // Only change code above this line\n}\n```\n\n#### 7-Implement insertion Sort\n\n```js\nfunction insertionSort(array) {\n  // Only change code below this line\n\n  for (let i = 1; i \u003c array.length; i++) {\n    let j = i;\n    while (j \u003e 0 \u0026\u0026 array[j] \u003c array[j - 1]) {\n      [array[j], array[j - 1]] = [array[j - 1], array[j]];\n      j--;\n    }\n  }\n  return array;\n  // Only change code above this line\n}\n```\n\n#### 8-Implement Quick Sort\n\n```js\nfunction quickSort(array) {\n  // Only change code below this line\n  if (array.length \u003c= 1) {\n    return array;\n  }\n  const last = array[array.length - 1];\n  const subArr = array.slice(0, array.length - 1);\n  const left = [];\n  const right = [];\n  for (let i = 0; i \u003c subArr.length; i++) {\n    if (subArr[i] \u003c last) {\n      left.push(subArr[i]);\n    } else {\n      right.push(subArr[i]);\n    }\n  }\n  return [...quickSort(left), last, ...quickSort(right)];\n\n  // Only change code above this line\n}\n```\n\n#### 9-Implement Merge Sort\n\n```js\nfunction mergeSort(array) {\n  // Only change code below this line\n  if (array.length \u003c= 1) {\n    return array;\n  }\n\n  if (array.length === 2) {\n    return merge([array[0]], [array[1]]);\n  }\n\n  const mid = Math.floor(array.length / 2);\n  const left = array.slice(0, mid);\n  const right = array.slice(mid);\n\n  return merge(mergeSort(left), mergeSort(right));\n\n  // Only change code above this line\n}\nfunction merge(left, right) {\n  let result = [];\n  let i = 0;\n  let j = 0;\n\n  while (i \u003c left.length \u0026\u0026 j \u003c right.length) {\n    if (left[i] \u003c right[j]) {\n      result.push(left[i]);\n      i++;\n    } else {\n      result.push(right[j]);\n      j++;\n    }\n  }\n  while (i \u003c left.length) {\n    result.push(left[i]);\n    i++;\n  }\n  while (j \u003c right.length) {\n    result.push(right[j]);\n    j++;\n  }\n\n  return result;\n}\n```\n\n#### 10-Implement Binary Search\n\n```js\nfunction binarySearch(searchList, value) {\n  let arrayPath = [];\n\n  const mid = Math.floor((searchList.length - 1) / 2);\n\n  if (searchList[mid] === value) {\n    return [searchList[mid]];\n  }\n  if (searchList.length \u003c= 1) {\n    return [null];\n  }\n  const left = searchList.slice(0, mid);\n  const right = searchList.slice(mid + 1);\n  arrayPath.push(searchList[mid]);\n\n  if (value \u003c searchList[mid]) {\n    arrayPath = arrayPath.concat(binarySearch(left, value));\n  } else if (value \u003e searchList[mid]) {\n    arrayPath = arrayPath.concat(binarySearch(right, value));\n  }\n\n  return arrayPath.includes(value) ? arrayPath : \"Value Not Found\";\n}\n```\n\n## Data Structures\n\n### 100% Completed\n\n![100% completed data structures](./Data%20Structures/completed.webp)\n\n### Lista de Data Structures\n\n#### 1-Stack\n\n```js\nfunction Stack() {\n  var collection = [];\n  this.print = function () {\n    console.log(collection);\n  };\n  // Only change code below this line\n\n  this.push = function (element) {\n    collection.push(element);\n  };\n\n  this.pop = function () {\n    return collection.pop();\n  };\n\n  this.peek = function () {\n    return collection[collection.length - 1];\n  };\n  this.isEmpty = function () {\n    return collection.length === 0;\n  };\n\n  this.clear = function () {\n    collection = [];\n  };\n\n  this.print = function () {\n    console.log(collection);\n  };\n\n  // Only change code above this line\n}\n```\n\n#### 2-Queue\n\n```js\nfunction Queue() {\n  var collection = [];\n  this.print = function () {\n    console.log(collection);\n  };\n  // Only change code below this line\n\n  this.enqueue = function (element) {\n    collection.push(element);\n  };\n  this.dequeue = function () {\n    return collection.shift();\n  };\n\n  this.front = function () {\n    return collection[0];\n  };\n  this.size = function () {\n    return collection.length;\n  };\n\n  this.isEmpty = function () {\n    return collection.length === 0;\n  };\n\n  // Only change code above this line\n}\n```\n\n#### 3-Priority Queue\n\n```js\nfunction PriorityQueue() {\n  this.collection = [];\n  this.printCollection = function () {\n    console.log(this.collection);\n  };\n  // Only change code below this line\n\n  this.enqueue = function (element) {\n    this.collection.push(element);\n  };\n\n  this.dequeue = function () {\n    const orderCollectiobyPriority = this.collection\n      .map((x, i) =\u003e [x[0], x[1], i])\n      .sort((a, b) =\u003e a[1] - b[1]);\n\n    const elementToRemove = orderCollectiobyPriority[0];\n    const indexToRemove = elementToRemove[2];\n    this.collection.splice(indexToRemove, 1);\n    return elementToRemove[0];\n  };\n\n  this.size = function () {\n    return this.collection.length;\n  };\n\n  this.isEmpty = function () {\n    return this.collection.length === 0;\n  };\n\n  this.front = function () {\n    const orderCollectiobyPriority = this.collection\n      .map((x, i) =\u003e [x[0], x[1], i])\n      .sort((a, b) =\u003e a[1] - b[1]);\n    return orderCollectiobyPriority[0][0];\n  };\n  // Only change code above this line\n}\n```\n\n#### 4-Circular Queue\n\n```js\nclass CircularQueue {\n  constructor(size) {\n    this.queue = [];\n    this.read = 0;\n    this.write = 0;\n    this.max = size - 1;\n\n    while (size \u003e 0) {\n      this.queue.push(null);\n      size--;\n    }\n  }\n\n  print() {\n    return this.queue;\n  }\n\n  enqueue(item) {\n    // Only change code below this line\n\n    if (this.queue[this.write] === null) {\n      const nextWrite = (this.write + 1) % (this.max + 1);\n      this.queue[this.write] = item;\n      this.write = nextWrite;\n\n      return item;\n    }\n    return null;\n    // Only change code above this line\n  }\n\n  dequeue() {\n    // Only change code below this line\n\n    if (this.queue[this.read] !== null) {\n      const nextRead = (this.read + 1) % (this.max + 1);\n      const item = this.queue[this.read];\n      this.queue[this.read] = null;\n      this.read = nextRead;\n      return item;\n    }\n    return null;\n    // Only change code above this line\n  }\n}\n```\n\n#### 5-Set\n\nClase Set con operaciones de agregación, eliminación, unión, intersección, diferencia y chequear si un set es subset de otro:\n\n```js\nclass Set {\n  constructor() {\n    // This will hold the set\n    this.dictionary = {};\n    this.length = 0;\n  }\n  // This method will check for the presence of an element and return true or false\n  has(element) {\n    return this.dictionary[element] !== undefined;\n  }\n  // This method will return all the values in the set\n  values() {\n    return Object.keys(this.dictionary);\n  }\n  // This method will add an element to the set\n  add(element) {\n    if (!this.has(element)) {\n      this.dictionary[element] = true;\n      this.length++;\n      return true;\n    }\n\n    return false;\n  }\n  // This method will remove an element from a set\n  remove(element) {\n    if (this.has(element)) {\n      delete this.dictionary[element];\n      this.length--;\n      return true;\n    }\n\n    return false;\n  }\n  // This method will return the size of the set\n  size() {\n    return this.length;\n  }\n  // This is our union method\n  union(set) {\n    const newSet = new Set();\n    this.values().forEach((value) =\u003e {\n      newSet.add(value);\n    });\n    set.values().forEach((value) =\u003e {\n      newSet.add(value);\n    });\n\n    return newSet;\n  }\n  // This is our intersection method\n  intersection(set) {\n    const newSet = new Set();\n\n    let largeSet;\n    let smallSet;\n    if (this.dictionary.length \u003e set.length) {\n      largeSet = this;\n      smallSet = set;\n    } else {\n      largeSet = set;\n      smallSet = this;\n    }\n\n    smallSet.values().forEach((value) =\u003e {\n      if (largeSet.dictionary[value]) {\n        newSet.add(value);\n      }\n    });\n\n    return newSet;\n  }\n\n  difference(set) {\n    const newSet = new Set();\n\n    this.values().forEach((value) =\u003e {\n      if (!set.dictionary[value]) {\n        newSet.add(value);\n      }\n    });\n\n    return newSet;\n  }\n  // Only change code below this line\n  isSubsetOf(otherSet) {\n    let isSubsetFlag = true;\n    for (let value of this.values()) {\n      if (otherSet.has(value)) {\n        isSubsetFlag = true;\n      } else {\n        isSubsetFlag = false;\n        break;\n      }\n    }\n\n    return isSubsetFlag;\n  }\n  // Only change code above this line\n}\n```\n\n#### 6-Map\n\n```js\nconst Map = function () {\n  this.collection = {};\n  // Only change code below this line\n\n  this.add = function (key, value) {\n    this.collection[key] = value;\n  };\n\n  this.remove = function (key) {\n    delete this.collection[key];\n  };\n\n  this.get = function (key) {\n    return this.collection[key];\n  };\n\n  this.has = function (key) {\n    return key in this.collection;\n  };\n\n  this.values = function () {\n    return Object.values(this.collection);\n  };\n\n  this.size = function () {\n    return Object.keys(this.collection).length;\n  };\n\n  this.clear = function () {\n    this.collection = {};\n  };\n\n  // Only change code above this line\n};\n```\n\n#### 7-Tabla Hash\n\nTabla hash con función de hasheo determinista:\n\n```js\nvar called = 0;\nvar hash = (string) =\u003e {\n  called++;\n  var hashed = 0;\n  for (var i = 0; i \u003c string.length; i++) {\n    hashed += string.charCodeAt(i);\n  }\n  return hashed;\n};\nvar HashTable = function () {\n  this.collection = {};\n  // Only change code below this line\n\n  this.add = function (key, value) {\n    const keyHash = hash(key);\n    if (!this.collection[keyHash]) {\n      this.collection[keyHash] = {\n        [key]: value,\n      };\n    } else {\n      this.collection[keyHash] = {\n        ...this.collection[keyHash],\n        [key]: value,\n      };\n    }\n  };\n\n  this.remove = function (key) {\n    const keyHash = hash(key);\n    const objAssociatedWithKey = this.collection[keyHash];\n    if (Object.keys(objAssociatedWithKey).length === 1) {\n      delete this.collection[keyHash];\n    } else {\n      delete this.collection[keyHash][key];\n    }\n  };\n\n  this.lookup = function (key) {\n    const keyHash = hash(key);\n    if (this.collection[keyHash]) {\n      return this.collection[keyHash][key];\n    }\n    return null;\n  };\n\n  // Only change code above this line\n};\n```\n\n#### 8- Linked List\n\n```js\nfunction LinkedList() {\n  var length = 0;\n  var head = null;\n\n  var Node = function (element) {\n    this.element = element;\n    this.next = null;\n  };\n\n  this.size = function () {\n    return length;\n  };\n\n  this.head = function () {\n    return head;\n  };\n\n  this.add = function (element) {\n    var node = new Node(element);\n    if (head === null) {\n      head = node;\n    } else {\n      var currentNode = head;\n\n      while (currentNode.next) {\n        currentNode = currentNode.next;\n      }\n\n      currentNode.next = node;\n    }\n\n    length++;\n  };\n\n  this.remove = function (element) {\n    var currentNode = head;\n    var previousNode;\n    if (currentNode.element === element) {\n      head = currentNode.next;\n    } else {\n      while (currentNode.element !== element) {\n        previousNode = currentNode;\n        currentNode = currentNode.next;\n      }\n\n      previousNode.next = currentNode.next;\n    }\n\n    length--;\n  };\n\n  // Only change code below this line\n\n  this.isEmpty = function () {\n    return length === 0;\n  };\n\n  this.indexOf = function (element) {\n    let currentNode = head;\n    let index = -1;\n\n    while (currentNode) {\n      index++;\n      if (currentNode.element === element) {\n        return index;\n      }\n      currentNode = currentNode.next;\n    }\n\n    return -1;\n  };\n\n  this.elementAt = function (index) {\n    let currentNode = head;\n    let count = 0;\n    while (currentNode) {\n      if (count === index) {\n        return currentNode.element;\n      }\n      currentNode = currentNode.next;\n      count++;\n    }\n  };\n\n  // Only change code above this line\n\n  this.addAt = function (index, element) {\n    if (index \u003c 0 || index \u003e length) {\n      return false;\n    } else {\n      const node = new Node(element);\n      if (index === 0) {\n        node.next = head;\n        head = node;\n        length++;\n        return element;\n      } else {\n        let currentNode = head;\n        let previousNode;\n        let i = 0;\n        while (i \u003c index) {\n          previousNode = currentNode;\n          currentNode = currentNode.next;\n          i++;\n        }\n\n        node.next = currentNode;\n        previousNode.next = node;\n        length++;\n\n        return element;\n      }\n    }\n  };\n}\n```\n\n#### 9-Doubly Linked List\n\n```js\nvar Node = function (data, prev) {\n  this.data = data;\n  this.prev = prev;\n  this.next = null;\n};\nvar DoublyLinkedList = function () {\n  this.head = null;\n  this.tail = null;\n  // Only change code below this line\n\n  this.add = function (data) {\n    if (this.head === null) {\n      this.head = new Node(data, null);\n      this.tail = this.head;\n    } else {\n      this.tail.next = new Node(data, this.tail);\n      this.tail = this.tail.next;\n    }\n  };\n\n  this.remove = function (data) {\n    if (this.head === null) return null;\n    else {\n      let node = this.head;\n      while (node !== null) {\n        if (node.data === data) {\n          if (node === this.head) {\n            this.head = node.next;\n            this.head.prev = null;\n          } else if (node === this.tail) {\n            this.tail = node.prev;\n            this.tail.next = null;\n          } else {\n            node.prev.next = node.next;\n            node.next.prev = node.prev;\n          }\n        }\n        node = node.next;\n      }\n    }\n  };\n  this.reverse = function () {\n    // recorrido desde la head hasta la tail\n    if (this.head === null) return null;\n    else {\n      let currentNode = this.head;\n      let previousNode = null;\n      while (currentNode !== null) {\n        [currentNode.next, currentNode.prev] = [previousNode, currentNode.next];\n        previousNode = currentNode;\n        currentNode = currentNode.prev;\n      }\n      [this.head, this.tail] = [this.tail, this.head];\n    }\n  };\n\n  this.reverse1 = function () {\n    //recorrido desde la tail hasta la head\n    if (this.head === null) return null;\n    else {\n      let currentNode = this.tail;\n      let nextNode = null;\n\n      while (currentNode !== null) {\n        [currentNode.next, currentNode.prev] = [currentNode.prev, nextNode];\n        nextNode = currentNode;\n        currentNode = currentNode.next;\n      }\n      [this.head, this.tail] = [this.tail, this.head];\n    }\n  };\n  // Only change code above this line\n};\n```\n\n#### 10-Binary Search Tree\n\n##### 10.1-Add a new element to a Binary Search Tree\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\nfunction BinarySearchTree() {\n  this.root = null;\n  // Only change code below this line\n  this.add = function (value) {\n    if (this.root === null) {\n      this.root = new Node(value);\n      return;\n    } else {\n      let currentNode = this.root;\n      while (currentNode) {\n        if (value \u003c currentNode.value) {\n          if (!currentNode.left) {\n            currentNode.left = new Node(value);\n            return;\n          } else {\n            currentNode = currentNode.left;\n          }\n        }\n        if (value \u003e currentNode.value) {\n          if (!currentNode.right) {\n            currentNode.right = new Node(value);\n            return;\n          } else {\n            currentNode = currentNode.right;\n          }\n        }\n        if (value === currentNode.value) {\n          return null;\n        }\n      }\n    }\n  };\n  // Only change code above this line\n}\n```\n\n##### 10.2-Find the Minimum and Maximum Value in a Binary Search Tree\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\nfunction BinarySearchTree() {\n  this.root = null;\n  // Only change code below this line\n\n  this.findMin = function () {\n    if (this.root === null) return null;\n    let currentNode = this.root;\n    let minValue = currentNode.value;\n    while (currentNode.left) {\n      minValue = currentNode.left.value;\n      currentNode = currentNode.left;\n    }\n    return minValue;\n  };\n\n  this.findMax = function () {\n    if (this.root === null) return null;\n    let currentNode = this.root;\n    let maxValue = currentNode.value;\n    while (currentNode.right) {\n      maxValue = currentNode.right.value;\n      currentNode = currentNode.right;\n    }\n    return maxValue;\n  };\n\n  // Only change code above this line\n}\n```\n\n##### 10.3-Check if an Element is Present in a Binary Search Tree\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\nfunction BinarySearchTree() {\n  this.root = null;\n  // Only change code below this line\n  this.isPresent = function (number) {\n    if (this.root === null) {\n      return false;\n    }\n    let currentNode = this.root;\n    while (currentNode !== null) {\n      if (currentNode.value === number) {\n        return true;\n      } else if (number \u003c currentNode.value) {\n        currentNode = currentNode.left;\n      } else if (number \u003e currentNode.value) {\n        currentNode = currentNode.right;\n      }\n    }\n\n    return false;\n  };\n  // Only change code above this line\n}\n```\n\n##### 10.4-Check if Tree is Binary Search Tree\n\nCreo algoritmo en base a lo señalado en el enunciado:\n\n\u003e The main distinction of a binary search tree is that the nodes are ordered in an organized fashion. Nodes have at most 2 child nodes (placed to the right and/or left) based on if the child node's value is greater than or equal to (right) or less than (left) the parent node.\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\nfunction BinarySearchTree() {\n  this.root = null;\n}\n\nfunction isBinarySearchTree(tree) {\n  // Only change code below this line\n\n  if (tree.root === null) return false;\n  if (tree.root instanceof Node) {\n    if (tree.root.left instanceof Node \u0026\u0026 tree.root.right === null) {\n      if (tree.root.left.value \u003e= tree.root.value) {\n        return false;\n      } else {\n        return isBinarySearchTree({ root: tree.root.left });\n      }\n    }\n    if (tree.root.left === null \u0026\u0026 tree.root.right instanceof Node) {\n      if (tree.root.right.value \u003c tree.root.value) {\n        return false;\n      } else {\n        return isBinarySearchTree({ root: tree.root.right });\n      }\n    }\n    if (tree.root.left instanceof Node \u0026\u0026 tree.root.right instanceof Node) {\n      if (\n        tree.root.left.value \u003e= tree.root.value ||\n        tree.root.right.value \u003c= tree.root.value\n      ) {\n        return false;\n      } else {\n        return (\n          isBinarySearchTree({ root: tree.root.left }) \u0026\u0026\n          isBinarySearchTree({ root: tree.root.right })\n        );\n      }\n    }\n\n    return true;\n  } else {\n    return false;\n  }\n  // Only change code above this line\n}\n```\n\n##### 10.5-Find the Minimum and Maximum Height of a Binary Search Tree\n\nAdemás, en base a la altura máxima y la altura mínima se calcula si el árbol esta balanceado o no. Se dice que esta balanceado cuando la diferencia sea a lo más 1:\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\nfunction BinarySearchTree() {\n  this.root = null;\n\n  // Only change code below this line\n\n  this.findMaxHeight = function () {\n    if (this.root === null) return -1;\n    function maxHeight(node) {\n      if (node === null) return 0;\n      if (node.left === null \u0026\u0026 node.right === null) return 0;\n      return Math.max(maxHeight(node.left), maxHeight(node.right)) + 1;\n    }\n    return maxHeight(this.root);\n  };\n\n  this.findMinHeight = function () {\n    if (this.root === null) return -1;\n    function minHeight(node) {\n      if (node.left === null \u0026\u0026 node.right === null) return 0;\n      if (node.left === null \u0026\u0026 node.right) return 0;\n      if (node.right === null \u0026\u0026 node.left) return 0;\n      return Math.min(minHeight(node.left), minHeight(node.right)) + 1;\n    }\n    return minHeight(this.root);\n  };\n\n  this.isBalanced = function () {\n    const maxHeight = this.findMaxHeight();\n    const minHeight = this.findMinHeight();\n\n    return maxHeight - minHeight \u003c= 1;\n  };\n\n  // Only change code above this line\n}\n```\n\n##### 10.6-Use Depth First Search in a Binary Search Tree\n\nSe crean los 3 métodos siguientes: **inorder**, **preorder** y **postorder** tal que:\n\n- In-order: muestra los valores desde el nodo más izquierdo y más abajo hacia la derecha\n- Pre-order: explora las raíces antes que las hojas desde la izquierda hacia la derecha\n- Post-order: explora todas las hojas antes que las raíces desde la izquierda hacia la derecha\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\nfunction BinarySearchTree() {\n  this.root = null;\n  // Only change code below this line\n\n  this.inorder = function () {\n    if (this.root === null) return null;\n    const result = [];\n\n    function traverse(node) {\n      if (!node.left \u0026\u0026 !node.right) {\n        result.push(node.value);\n      }\n      if (node.left \u0026\u0026 !node.right) {\n        traverse(node.left);\n        result.push(node.value);\n      }\n      if (!node.left \u0026\u0026 node.right) {\n        result.push(node.value);\n        traverse(node.right);\n      }\n      if (node.left \u0026\u0026 node.right) {\n        traverse(node.left);\n        result.push(node.value);\n        traverse(node.right);\n      }\n    }\n\n    traverse(this.root);\n    return result;\n  };\n\n  this.preorder = function () {\n    if (this.root === null) return null;\n    const result = [];\n    result.push(this.root.value);\n    function traverse(node) {\n      if (node.left \u0026\u0026 node.right) {\n        result.push(node.left.value);\n        traverse(node.left);\n        result.push(node.right.value);\n        traverse(node.right);\n      }\n      if (node.left \u0026\u0026 !node.right) {\n        result.push(node.left.value);\n        traverse(node.left);\n      }\n      if (!node.left \u0026\u0026 node.right) {\n        result.push(node.right.value);\n        traverse(node.right);\n      }\n    }\n\n    traverse(this.root);\n    return result;\n  };\n\n  this.postorder = function () {\n    if (this.root === null) return null;\n    const result = [];\n    function traverse(node) {\n      if (!node.left \u0026\u0026 !node.right) {\n        result.push(node.value);\n      }\n      if (node.left \u0026\u0026 !node.right) {\n        traverse(node.left);\n        result.push(node.value);\n      }\n      if (!node.left \u0026\u0026 node.right) {\n        traverse(node.right);\n        result.push(node.value);\n      }\n      if (node.left \u0026\u0026 node.right) {\n        traverse(node.left);\n        traverse(node.right);\n        result.push(node.value);\n      }\n    }\n\n    traverse(this.root);\n    return result;\n  };\n\n  // Only change code above this line\n}\n```\n\n##### 10.7-Use Breadth First Search in a Binary Search Tree\n\nAlgoritmo implementado en base a lo señalado en el enunciado:\n\n\u003e In this method, we start by adding the root node to a queue. Then we begin a loop where we dequeue the first item in the queue, add it to a new array, and then inspect both its child subtrees. If its children are not null, they are each enqueued. This process continues until the queue is empty.\n\n```js\nvar displayTree = (tree) =\u003e console.log(JSON.stringify(tree, null, 2));\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\nfunction BinarySearchTree() {\n  this.root = null;\n\n  // Only change code below this line\n\n  this.levelOrder = function () {\n    if (this.root === null) return null;\n    const values = [];\n    const queue = [this.root];\n\n    while (queue.length) {\n      const node = queue.shift();\n      values.push(node.value);\n      if (node.left) queue.push(node.left);\n      if (node.right) queue.push(node.right);\n    }\n    return values;\n  };\n\n  this.reverseLevelOrder = function () {\n    if (this.root === null) return null;\n    const values = [];\n    const queue = [this.root];\n    while (queue.length) {\n      const node = queue.shift();\n      values.push(node.value);\n      if (node.right) queue.push(node.right);\n      if (node.left) queue.push(node.left);\n    }\n    return values;\n  };\n\n  // Only change code above this line\n}\n```\n\n##### 10.8-Delete a Leaf Node in a Binary Search Tree\n\nImplementación de algoritmo que elimina nodos **sin hijos**:\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\n\nfunction BinarySearchTree() {\n  this.root = null;\n\n  // Only change code below this line\n\n  this.remove = function (value) {\n    let nodeToDelete = null;\n    let parentNode = null;\n\n    let currentNode = this.root;\n\n    function findNodeToDelete(node) {\n      if (node === null) return null;\n      if (node.value === value) {\n        nodeToDelete = node;\n      } else if (value \u003c node.value) {\n        parentNode = node;\n        findNodeToDelete(node.left);\n      } else if (value \u003e node.value) {\n        parentNode = node;\n        findNodeToDelete(node.right);\n      }\n    }\n\n    function childrenCount(node) {\n      if (node.left \u0026\u0026 node.right) {\n        return 2;\n      } else if (node.left || node.right) {\n        return 1;\n      } else {\n        return 0;\n      }\n    }\n\n    if (this.root === null) return null;\n\n    if (currentNode.value === value) {\n      this.root = null;\n      return null;\n    } else {\n      findNodeToDelete(currentNode);\n      if (!nodeToDelete) {\n        return null;\n      } else {\n        if (childrenCount(nodeToDelete) === 0) {\n          if (parentNode.left === nodeToDelete) {\n            parentNode.left = null;\n          } else if (parentNode.right === nodeToDelete) {\n            parentNode.right = null;\n          }\n        }\n      }\n    }\n  };\n}\n```\n\n##### 10.9-Delete a Node with One Child in a Binary Search Tree\n\nImplementación de algoritmo que elimina nodo con **solo un hijo**:\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\n\nfunction BinarySearchTree() {\n  this.root = null;\n\n  this.remove = function (value) {\n    if (this.root === null) {\n      return null;\n    }\n    var target;\n    var parent = null;\n    var direction = null;\n    // Find the target value and its parent\n    (function findValue(node = this.root) {\n      if (value == node.value) {\n        target = node;\n      } else if (value \u003c node.value \u0026\u0026 node.left !== null) {\n        parent = node;\n        direction = \"left\";\n        return findValue(node.left);\n      } else if (value \u003c node.value \u0026\u0026 node.left === null) {\n        return null;\n      } else if (value \u003e node.value \u0026\u0026 node.right !== null) {\n        parent = node;\n        direction = \"right\";\n        return findValue(node.right);\n      } else {\n        return null;\n      }\n    }).bind(this)();\n    if (target === null) {\n      return null;\n    }\n    // Count the children of the target to delete\n    var children =\n      (target?.left !== null ? 1 : 0) + (target?.right !== null ? 1 : 0);\n    // Case 1: Target has no children\n    if (children === 0) {\n      if (target == this.root) {\n        this.root = null;\n      } else {\n        if (parent.left == target) {\n          parent.left = null;\n        } else {\n          parent.right = null;\n        }\n      }\n    }\n    // Case 2: Target has one child\n    // Only change code below this line\n    if (children == 1) {\n      if (target !== this.root) {\n        if (direction == \"left\") {\n          parent.left = target.left !== null ? target.left : target.right;\n        } else {\n          parent.right = target.right !== null ? target.right : target.left;\n        }\n      } else {\n        this.root = target.left !== null ? target.left : target.right;\n      }\n    }\n  };\n}\n```\n\n##### 10.10-Delete a Node with Two Children in a Binary Search Tree\n\nImplementación de algoritmo que elimina un nodo que posee **dos hijos**. La eliminación y la posterior reconfiguración del árbol binario se realiza en base a lo señalado en el enunciado del problema siguiente:\n\n\u003e Removing nodes that have two children is the hardest case to implement. Removing a node like this produces two subtrees that are no longer connected to the original tree structure. How can we reconnect them? One method is to find the smallest value in the right subtree of the target node and replace the target node with this value. Selecting the replacement in this way ensures that it is greater than every node in the left subtree it becomes the new parent of but also less than every node in the right subtree it becomes the new parent of. Once this replacement is made the replacement node must be removed from the right subtree. Even this operation is tricky because the replacement may be a leaf or it may itself be the parent of a right subtree. If it is a leaf we must remove its parent's reference to it. Otherwise, it must be the right child of the target. In this case, we must replace the target value with the replacement value and make the target reference the replacement's right child.\n\nEs decir, si el nodo a eliminar tiene 2 hijos, entonces en el nodo derecho (subárbol) se busca el nodo con el menor valor. Si ese nodo no tiene hijos, entonces se reemplaza el valor de este nodo en el valor del nodo a eliminar luego dicho nodo(el nodo de menor valor) se elimina y el padre que apuntaba a este nodo hijo ahora apunta a nulo. Ahora bien, si ese nodo (el nodo de menor valor) tiene un hijo, ese hijo **SIEMPRE** estará ubicado a la derecha ya que si estuviera a la izquierda, entonces el nodo que se esta analizando no sería mínimo por lo que existiría una contradicción ya que el nodo es mínimo. Como el nodo tiene un nodo hijo a la derecha, se reemplaza el valor de ese nodo(el nodo de menor valor) en el nodo a eliminar y el puntero del nodo a eliminar derecho ahora apunta al nodo hijo derecho del nodo que posee menor valor.\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\n\nfunction BinarySearchTree() {\n  this.root = null;\n\n  this.remove = function (value) {\n    if (this.root === null) {\n      return null;\n    }\n    var target;\n    var parent = null;\n    // Find the target value and its parent\n    (function findValue(node = this.root) {\n      if (value == node.value) {\n        target = node;\n      } else if (value \u003c node.value \u0026\u0026 node.left !== null) {\n        parent = node;\n        return findValue(node.left);\n      } else if (value \u003c node.value \u0026\u0026 node.left === null) {\n        return null;\n      } else if (value \u003e node.value \u0026\u0026 node.right !== null) {\n        parent = node;\n        return findValue(node.right);\n      } else {\n        return null;\n      }\n    }).bind(this)();\n    if (target === null) {\n      return null;\n    }\n    // Count the children of the target to delete\n    var children =\n      (target.left !== null ? 1 : 0) + (target.right !== null ? 1 : 0);\n    // Case 1: Target has no children\n    if (children === 0) {\n      if (target == this.root) {\n        this.root = null;\n      } else {\n        if (parent.left == target) {\n          parent.left = null;\n        } else {\n          parent.right = null;\n        }\n      }\n    }\n    // Case 2: Target has one child\n    else if (children == 1) {\n      var newChild = target.left !== null ? target.left : target.right;\n      if (parent === null) {\n        target.value = newChild.value;\n        target.left = null;\n        target.right = null;\n      } else if (newChild.value \u003c parent.value) {\n        parent.left = newChild;\n      } else {\n        parent.right = newChild;\n      }\n      target = null;\n    }\n    // Case 3: Target has two children\n    // Only change code below this line\n    else if (children == 2) {\n      let targetMin = null;\n      let targetMinParent = null;\n\n      function findTargetMin(node = target.right, parent = target) {\n        if (node.left === null) {\n          targetMin = node;\n          targetMinParent = parent;\n        } else {\n          return findTargetMin(node.left, node);\n        }\n      }\n\n      findTargetMin();\n\n      target.value = targetMin.value;\n      const childrenTargetMin =\n        (targetMin.left !== null ? 1 : 0) + (targetMin.right !== null ? 1 : 0);\n      if (childrenTargetMin === 0) {\n        if (targetMinParent.left == targetMin) {\n          targetMinParent.left = null;\n        } else {\n          targetMinParent.right = null;\n        }\n      }\n\n      if (childrenTargetMin == 1) {\n        target.right = targetMin.right;\n      }\n    }\n  };\n}\n```\n\n##### 10.11-Invert a Binary Tree\n\nHe creado dos algoritmos diferentes que hacen lo mismo invertir un árbol binario. Un árbol binario invertido se dice que cumple con lo siguiente:\n\n\u003e Here will we create a function to invert a binary tree. Given a binary tree, we want to produce a new tree that is equivalently the mirror image of this tree. Running an inorder traversal on an inverted tree will explore the nodes in reverse order when compared to the inorder traversal of the original tree.\n\nEs decir, en un recorrido **inorder** sobre árbol binario invertido, los nodos son explorados en un orden inverso cuando se compara a un recorrido **inorder** sobre el árbol binario original.\n\n```js\nfunction Node(value) {\n  this.value = value;\n  this.left = null;\n  this.right = null;\n}\nfunction BinarySearchTree() {\n  this.root = null;\n\n  // Only change code below this line\n\n  this.invert = function () {\n    if (this.root === null) return null;\n    const queue = [this.root];\n    while (queue.length) {\n      const node = queue.shift();\n      if (node.left) queue.push(node.left);\n      if (node.right) queue.push(node.right);\n      [node.left, node.right] = [node.right, node.left];\n    }\n    return this;\n  };\n\n  this.invert1 = function () {\n    // otra manera de hacer lo mismo que el método invert\n    if (this.root === null) return null;\n\n    function invert(node) {\n      if (node === null) return null;\n      [node.left, node.right] = [invert(node.right), invert(node.left)];\n      return node;\n    }\n    return invert(this.root);\n  };\n\n  // Only change code above this line\n}\n```\n\n#### 11-Create a Trie Search Tree\n\nSe crea un **Trie Search Tree** en base al enunciado del problema:\n\n\u003e Here we will move on from binary search trees and take a look at another type of tree structure called a trie. A trie is an ordered search tree commonly used to hold strings, or more generically associative arrays or dynamic datasets in which the keys are strings. They are very good at storing sets of data when many keys will have overlapping prefixes, for example, all the words in a dictionary. Unlike a binary tree, nodes are not associated with actual values. Instead, the path to a node represents a specific key. For instance, if we wanted to store the string code in a trie, we would have four nodes, one for each letter: c — o — d — e. Following that path through all these nodes will then create code as a string — that path is the key we stored. Then, if we wanted to add the string coding, it would share the first three nodes of code before branching away after the d. In this way, large datasets can be stored very compactly. In addition, search can be very quick because it is effectively limited to the length of the string you are storing. Furthermore, unlike binary trees a node can store any number of child nodes. As you might have guessed from the above example, some metadata is commonly stored at nodes that hold the end of a key so that on later traversals that key can still be retrieved. For instance, if we added codes in our example above we would need some way to know that the e in code represents the end of a key that was previously entered. Otherwise, this information would effectively be lost when we add codes.\n\nSe pide crear los siguientes tres métodos **add**, **print** y **isWord** en base a lo siguiente:\n\n\u003e Let's create a trie to store words. It will accept words through an add method and store these in a trie data structure. It will also allow us to query if a given string is a word with an isWord method, and retrieve all the words entered into the trie with a print method. isWord should return a boolean value and print should return an array of all these words as string values. In order for us to verify that this data structure is implemented correctly, we've provided a Node structure for each node in the tree. Each node will be an object with a keys property which is a JavaScript Map object. This will hold the individual letters that are valid keys of each node. We've also created an end property on the nodes that can be set to true if the node represents the termination of a word.\n\n```js\nvar Node = function () {\n  this.keys = new Map();\n  this.end = false;\n  this.setEnd = function () {\n    this.end = true;\n  };\n  this.isEnd = function () {\n    return this.end;\n  };\n};\nvar Trie = function () {\n  // Only change code below this line\n  this.root = new Node();\n  this.add = function (word) {\n    let currentNode = this.root;\n    let i = 0;\n\n    while (i \u003c= word.length) {\n      if (i === word.length) {\n        currentNode.setEnd();\n        break;\n      }\n      if (!currentNode.keys.has(word[i])) {\n        currentNode.keys.set(word[i], new Node());\n      }\n      currentNode = currentNode.keys.get(word[i]);\n      i++;\n    }\n  };\n\n  this.print = function () {\n    const allWords = [];\n    const printNode = (node, word = \"\") =\u003e {\n      if (node.isEnd()) {\n        allWords.push(word);\n      }\n      node.keys.forEach((value, key) =\u003e {\n        printNode(value, word + key);\n      });\n    };\n    printNode(this.root);\n    return allWords;\n  };\n\n  this.isWord = function (word) {\n    let currentNode = this.root;\n    let i = 0;\n    while (i \u003c= word.length) {\n      if (i === word.length) {\n        return currentNode.isEnd();\n      } else {\n        if (!currentNode.keys.has(word[i])) {\n          return false;\n        }\n        currentNode = currentNode.keys.get(word[i]);\n        i++;\n      }\n    }\n  };\n  // Only change code above this line\n};\n```\n\nCuando se agrega una palabra, el nodo asociado a la última letra posee la propiedad **end** igual a true. Para mostrar todas las palabras, se recorren todos los nodos y se van uniendo las letras hasta el nodo asociado a la última letra el cual posee la propiedad end como true. Para chequear si una palabra existe, se procede a recorrer cada nodo y si no existe la clave o si al llegar al nodo que posee la última letra, la propiedad end es false entonces la palabra no existe, en caso contrario si existe.\n\n#### 12-Binary Heap\n\n##### 12.1-Insert an Element into a Max Heap\n\nUn max heap es lo siguiente:\n\n\u003e Now we will move on to another tree data structure, the binary heap. A binary heap is a partially ordered binary tree which satisfies the heap property. The heap property specifies a relationship between parent and child nodes. You may have a max heap, in which all parent nodes are greater than or equal to their child nodes, or a min heap, in which the reverse is true. Binary heaps are also complete binary trees. This means that all levels of the tree are fully filled and if the last level is partially filled it is filled from left to right.\n\u003e\n\u003e While binary heaps may be implemented as tree structures with nodes that contain left and right references, the partial ordering according to the heap property allows us to represent the heap with an array. The parent-children relationship is what we're interested in and with simple arithmetic we can compute the children of any parent and the parent of any child node.\n\u003e\n\u003e For instance, consider this array representation of a binary min heap:\n\u003e\n\u003e [ 6, 22, 30, 37, 63, 48, 42, 76 ]\n\u003e\n\u003e The root node is the first element, 6. Its children are 22 and 30. If we look at the relationship between the array indices of these values, for index i the children are 2*i + 1 and 2 * i + 2. Similarly, the element at index 0 is the parent of these two children at indices 1 and 2. More generally, we can find the parent of a node at any index with the following: Math.floor((i - 1) / 2). These patterns will hold true as the binary tree grows to any size. Finally, we can make a slight adjustment to make this arithmetic even easier by skipping the first element in the array. Doing this creates the following relationship for any element at a given index i:\n\u003e\n\u003e Example array representation:\n\u003e\n\u003e [ null, 6, 22, 30, 37, 63, 48, 42, 76 ]\n\u003e\n\u003e An element's left child: i \\* 2\n\u003e\n\u003e An element's right child: i \\* 2 + 1\n\u003e\n\u003e An element's parent: Math.floor(i / 2)\n\u003e\n\u003e Once you wrap your head around the math, using an array representation is very useful because node locations can be quickly determined with this arithmetic and memory usage is diminished because you don't need to maintain references to child nodes.\n\nSe pide crear un **Max Heap** en base a las siguientes instrucciones:\n\n\u003e Instructions: Here we will create a max heap. Start by just creating an insert method which adds elements to our heap. During insertion, it is important to always maintain the heap property. For a max heap this means the root element should always have the greatest value in the tree and all parent nodes should be greater than their children. For an array implementation of a heap, this is typically accomplished in three steps:\n\u003e\n\u003e -Add the new element to the end of the array\n\u003e\n\u003e -If the element is larger than its parent, switch them.\n\u003e\n\u003e -Continue switching until the new element is either smaller than its parent or you reach the root of the tree.\n\u003e\n\u003e Finally, add a print method which returns an array of all the items that have been added to the heap.\n\n```js\nvar MaxHeap = function () {\n  // Only change code below this line\n  this.maxheap = [];\n  this.insert = function (element) {\n    if (this.maxheap.length === 0) {\n      this.maxheap.push(null);\n      this.maxheap.push(element);\n    } else {\n      this.maxheap.push(element);\n      let index = this.maxheap.length - 1;\n      while (\n        this.maxheap[index] \u003e this.maxheap[Math.floor(index / 2)] \u0026\u0026\n        index \u003e 1\n      ) {\n        [this.maxheap[Math.floor(index / 2)], this.maxheap[index]] = [\n          this.maxheap[index],\n          this.maxheap[Math.floor(index / 2)],\n        ];\n        index = Math.floor(index / 2);\n      }\n    }\n\n    return element;\n  };\n\n  this.print = function () {\n    return this.maxheap.slice(1);\n  };\n  // Only change code above this line\n};\n```\n\n##### 12.2-Remove an Element from a Max Heap\n\nLas instrucciones de implementación del algoritmo de eliminación son las siguientes:\n\n\u003e Now that we can add elements to our heap let's see how we can remove elements. Removing and inserting elements both require similar logic. In a max heap you will usually want to remove the greatest value, so this involves simply extracting it from the root of our tree. This will break the heap property of our tree, so we must reestablish it in some way. Typically, for a max heap this is done in the following way:\n\u003e\n\u003e -Move the last element in the heap into the root position.\n\u003e\n\u003e -If either child of the root is greater than it, swap the root with the child of greater value.\n\u003e\n\u003e -Continue swapping until the parent is greater than both children or you reach the last level in the tree.\n\nLas instrucciones específicas de cómo implementar el algoritmo en el problema son la siguientes:\n\n\u003e Instructions: Add a method to our max heap called remove. This method should return the greatest value that has been added to our max heap and remove it from the heap. It should also reorder the heap so the heap property is maintained. After removing an element, the next greatest element remaining in the heap should become the root.\n\n```js\nconst MaxHeap = function () {\n  this.heap = [];\n  this.parent = (index) =\u003e {\n    return Math.floor((index - 1) / 2);\n  };\n  this.insert = (element) =\u003e {\n    this.heap.push(element);\n    this.heapifyUp(this.heap.length - 1);\n  };\n  this.heapifyUp = (index) =\u003e {\n    let currentIndex = index,\n      parentIndex = this.parent(currentIndex);\n    while (\n      currentIndex \u003e 0 \u0026\u0026\n      this.heap[currentIndex] \u003e this.heap[parentIndex]\n    ) {\n      this.swap(currentIndex, parentIndex);\n      currentIndex = parentIndex;\n      parentIndex = this.parent(parentIndex);\n    }\n  };\n  this.swap = (index1, index2) =\u003e {\n    [this.heap[index1], this.heap[index2]] = [\n      this.heap[index2],\n      this.heap[index1],\n    ];\n  };\n  this.print = () =\u003e {\n    return this.heap;\n  };\n  // Only change code below this line\n\n  this.remove = () =\u003e {\n    const maxValue = this.heap[0];\n    this.heap[0] = this.heap[this.heap.length - 1];\n    this.heap.pop();\n    let i = 0;\n    while (i \u003c this.heap.length) {\n      const leftChildIndex = 2 * i + 1;\n      const rightChildIndex = 2 * i + 2;\n\n      function findMaxChildIndex(leftChildIndex, rightChildIndex) {\n        if (leftChildIndex === this.heap.length - 1) {\n          return leftChildIndex;\n        }\n        if (leftChildIndex \u003e this.heap.length - 1) return this.heap.length;\n\n        if (this.heap[leftChildIndex] \u003e this.heap[rightChildIndex]) {\n          return leftChildIndex;\n        } else {\n          return rightChildIndex;\n        }\n      }\n      findMaxChildIndex = findMaxChildIndex.bind(this);\n\n      const maxChildIndex = findMaxChildIndex(leftChildIndex, rightChildIndex);\n      if (\n        maxChildIndex \u003c this.heap.length \u0026\u0026\n        this.heap[i] \u003c this.heap[maxChildIndex]\n      ) {\n        this.swap(i, maxChildIndex);\n        i = maxChildIndex;\n      } else {\n        break;\n      }\n    }\n\n    return maxValue;\n  };\n\n  // Only change code above this line\n};\n```\n\n##### 12.3-Implement Heap Sort with a Min Heap\n\nSe implementa un algoritmo heap sort a partir de un min heap. Las instrucciones de cómo crear el algoritmo son las siguientes:\n\n\u003e Now that we can add and remove elements let's see some of the applications heaps can be used for. Heaps are commonly used to implement priority queues because they always store an item of greatest or least value in first position. In addition, they are used to implement a sorting algorithm called heap sort. We'll see how to do this here. Heap sort uses a min heap, the reverse of a max heap. A min heap always stores the element of least value in the root position.\n\u003e\n\u003e Heap sort works by taking an unsorted array, adding each item in the array into a min heap, and then extracting every item out of the min heap into a new array. The min heap structure ensures that the new array will contain the original items in least to greatest order. This is one of the most efficient sorting algorithms with average and worst case performance of O(nlog(n)).\n\nLas instrucciones para implementar la clase MinHeap y sus métodos que permitan realizar el sorting son las siguientes:\n\n\u003e Let's implement heap sort with a min heap. Feel free to adapt your max heap code here. Create an object MinHeap with insert, remove, and sort methods. The sort method should return an array of all the elements in the min heap sorted from smallest to largest.\n\n```js\nvar MinHeap = function () {\n  // Only change code below this line\n  this.heap = [];\n  this.insert = function (value) {\n    if (this.heap.length === 0) {\n      this.heap.push(value);\n    } else {\n      this.heap.push(value);\n      let index = this.heap.length - 1;\n      while (\n        this.heap[index] \u003c this.heap[Math.floor((index - 1) / 2)] \u0026\u0026\n        index \u003e 0\n      ) {\n        [this.heap[Math.floor((index - 1) / 2)], this.heap[index]] = [\n          this.heap[index],\n          this.heap[Math.floor((index - 1) / 2)],\n        ];\n        index = Math.floor((index - 1) / 2);\n      }\n    }\n  };\n\n  this.remove = function () {\n    const minValue = this.heap[0];\n    this.heap[0] = this.heap[this.heap.length - 1];\n    this.heap.pop();\n\n    let i = 0;\n\n    while (i \u003c this.heap.length) {\n      let leftChildIndex = 2 * i + 1;\n      let rightChildIndex = 2 * i + 2;\n      let minIndex = i;\n\n      function findMinChildIndex(leftChildIndex, rightChildIndex) {\n        if (leftChildIndex === this.heap.length - 1) {\n          return leftChildIndex;\n        }\n\n        if (leftChildIndex \u003e this.heap.length - 1) {\n          return this.heap.length;\n        }\n\n        if (this.heap[leftChildIndex] \u003c this.heap[rightChildIndex]) {\n          return leftChildIndex;\n        } else {\n          return rightChildIndex;\n        }\n      }\n      findMinChildIndex = findMinChildIndex.bind(this);\n      const minChildIndex = findMinChildIndex(leftChildIndex, rightChildIndex);\n\n      if (\n        minChildIndex \u003c this.heap.length \u0026\u0026\n        this.heap[i] \u003e this.heap[minChildIndex]\n      ) {\n        [this.heap[i], this.heap[minChildIndex]] = [\n          this.heap[minChildIndex],\n          this.heap[i],\n        ];\n        i = minChildIndex;\n      } else {\n        break;\n      }\n    }\n  };\n\n  this.sort = function () {\n    const sorted = [];\n    while (this.heap.length \u003e 0) {\n      sorted.push(this.heap[0]);\n      this.remove();\n    }\n\n    return sorted;\n  };\n  // Only change code above this line\n};\n```\n\n#### 13-Graphs\n\n##### 13.1-Adjacency List\n\nSe define una adjacency list según lo siguiente:\n\n\u003e Graphs can be represented in different ways. Here we describe one way, which is called an adjacency list. An adjacency list is essentially a bulleted list where the left side is the node and the right side lists all the other nodes it's connected to. Below is a representation of an adjacency list.\n\n\u003e Node1: Node2, Node3\n\u003e\n\u003e Node2: Node1\n\u003e\n\u003e Node3: Node1\n\n\u003e Above is an undirected graph because Node1 is connected to Node2 and Node3, and that information is consistent with the connections Node2 and Node3 show. An adjacency list for a directed graph would mean each row of the list shows direction. If the above was directed, then Node2: Node1 would mean there the directed edge is pointing from Node2 towards Node1. We can represent the undirected graph above as an adjacency list by putting it within a JavaScript object.\n\n```js\nvar undirectedG = {\n  Node1: [\"Node2\", \"Node3\"],\n  Node2: [\"Node1\"],\n  Node3: [\"Node1\"],\n};\n```\n\nThis can also be more simply represented as an array where the nodes just have numbers rather than string labels.\n\n```js\nvar undirectedGArr = [\n  [1, 2], // Node1\n  [0], // Node2\n  [0], // Node3\n];\n```\n\nSe pide crear lo siguiente:\n\n\u003e Create a social network as an undirected graph with 4 nodes/people named James, Jill, Jenny, and Jeff. There are edges/relationships between James and Jeff, Jill and Jenny, and Jeff and Jenny.\n\n```js\nvar undirectedAdjList = {\n  James: [\"Jeff\"],\n  Jill: [\"Jenny\"],\n  Jeff: [\"Jenny\", \"James\"],\n  Jenny: [\"Jill\", \"Jeff\"],\n};\n```\n\n##### 13.2-Adjacency Matrix\n\nSe pide crear lo siguiente:\n\n\u003e Create an adjacency matrix of an undirected graph with five nodes. This matrix should be in a multi-dimensional array. These five nodes have relationships between the first and fourth node, the first and third node, the third and fifth node, and the fourth and fifth node. All edge weights are one.\n\n```js\nvar adjMatUndirected = [\n  [0, 0, 1, 1, 0],\n  [0, 0, 0, 0, 0],\n  [1, 0, 0, 0, 1],\n  [1, 0, 0, 0, 1],\n  [0, 0, 1, 1, 0],\n];\n```\n\n##### 13.3-Incidence Matrix\n\nSe pide crear lo siguiente:\n\n\u003e Create an incidence matrix of an undirected graph with five nodes and four edges. This matrix should be in a multi-dimensional array.\n\u003e\n\u003e These five nodes have the following relationships. The first edge is between the first and second node. The second edge is between the second and third node. The third edge is between the third and fifth node. The fourth edge is between the fourth and second node. All edge weights are one and the edge order matters.\n\n```js\nvar incMatUndirected = [\n  [1, 0, 0, 0],\n  [1, 1, 0, 1],\n  [0, 1, 1, 0],\n  [0, 0, 0, 1],\n  [0, 0, 1, 0],\n];\n```\n\n##### 13.4-Breadth-First Search\n\nEn base a lo señalado en la explicación del problema:\n\n\u003e So far, we've learned different ways of creating representations of graphs. What now? One natural question to have is what are the distances between any two nodes in the graph? Enter graph traversal algorithms.\n\u003e\n\u003e Traversal algorithms are algorithms to traverse or visit nodes in a graph. One type of traversal algorithm is the breadth-first search algorithm.\n\u003e\n\u003e This algorithm starts at one node and visits all its neighbors that are one edge away. It then goes on to visit each of their neighbors and so on until all nodes have been reached.\n\u003e\n\u003e An important data structure that will help implement the breadth-first search algorithm is the queue. This is an array where you can add elements to one end and remove elements from the other end. This is also known as a FIFO or First-In-First-Out data structure.\n\u003e\n\u003e The grey shading represents a node getting added into the queue and the black shading represents a node getting removed from the queue. See how every time a node gets removed from the queue (node turns black), all their neighbors get added into the queue (node turns grey).\n\u003e\n\u003e To implement this algorithm, you'll need to input a graph structure and a node you want to start at.\n\u003e\n\u003e First, you'll want to be aware of the distances from, or number of edges away from, the start node. You'll want to start all your distances with some large number, like Infinity. This prevents counting issues for when a node may not be reachable from your start node. Next, you'll want to go from the start node to its neighbors. These neighbors are one edge away and at this point you should add one unit of distance to the distances you're keeping track of.\n\nSe solicita crear lo siguiente:\n\n\u003e Write a function bfs() that takes an adjacency matrix graph (a two-dimensional array) and a node label root as parameters. The node label will just be the integer value of the node between 0 and n - 1, where n is the total number of nodes in the graph.\n\u003e\n\u003e Your function will output a JavaScript object key-value pairs with the node and its distance from the root. If the node could not be reached, it should have a distance of Infinity.\n\nMi implementación del algoritmo es la siguiente:\n\n```js\nfunction bfs(graph, root) {\n  // graph is a adjacency matrix graph\n  let nodesLen = {};\n  const queue = [root];\n  nodesLen[root] = 0;\n  while (queue.length) {\n    const node = queue.shift();\n\n    for (let i = 0; i \u003c graph[node].length; i++) {\n      if (graph[node][i] === 1 \u0026\u0026 nodesLen[i] === undefined) {\n        nodesLen[i] = nodesLen[node] + 1;\n        graph[i][node] = 0;\n        graph[node][i] = 0;\n        queue.push(i);\n      }\n    }\n  }\n  let unreacheableValue = Infinity;\n  for (let i = 0; i \u003c graph.length; i++) {\n    if (nodesLen[i] === undefined) {\n      nodesLen[i] = unreacheableValue;\n    }\n  }\n\n  return nodesLen;\n}\n```\n\n##### 13.5-Depth-First Search\n\nEn base a la explicación dada previo al ejercicio:\n\n\u003e Similar to breadth-first search, here we will learn about another graph traversal algorithm called depth-first search.\n\u003e\n\u003e Whereas the breadth-first search searches incremental edge lengths away from the source node, depth-first search first goes down a path of edges as far as it can.\n\u003e\n\u003e Once it reaches one end of a path, the search will backtrack to the last node with an un-visited edge path and continue searching.\n\u003e\n\u003e The animation below shows how the algorithm works. The algorithm starts with the top node and visits the nodes in the numbered order.\n\u003e\n\u003e Notice how, unlike breadth-first search, every time a node is visited, it doesn't visit all of its neighbors. Instead, it first visits one of its neighbors and continues down that path until there are no more nodes to be visited on that path.\n\u003e\n\u003e To implement this algorithm, you'll want to use a stack. A stack is an array where the last element added is the first to be removed. This is also known as a Last-In-First-Out data structure. A stack is helpful in depth-first search algorithms because, as we add neighbors to the stack, we want to visit the most recently added neighbors first and remove them from the stack.\n\u003e\n\u003e A simple output of this algorithm is a list of nodes which are reachable from a given node. Therefore, you'll also want to keep track of the nodes you visit.\n\nSe pide realizar lo siguiente:\n\n\u003e Write a function dfs() that takes an undirected, adjacency matrix graph and a node label root as parameters. The node label will just be the numeric value of the node between 0 and n - 1, where n is the total number of nodes in the graph.\n\u003e\n\u003e Your function should output an array of all nodes reachable from root.\n\n```js\nfunction dfs(graph, root) {\n  const nodesRemoved = [];\n  const stack = [root];\n\n  while (stack.length) {\n    const node = stack.pop();\n    if (nodesRemoved.includes(node)) {\n      continue;\n    }\n    nodesRemoved.push(node);\n    for (let i = 0; i \u003c graph[node].length; i++) {\n      if (graph[node][i] === 1) {\n        graph[i][node] = 0; // cuando se ha considerado el nodo i conectado al node ya no es necesario considerarlo en el grafo\n        graph[node][i] = 0;\n        stack.push(i);\n      }\n    }\n  }\n  return nodesRemoved;\n}\n```\n\nMi algoritmo empieza a recorrer desde el nodo root, se almacena su valor en el array **nodesRemoved** solo si no existe (los nodos a los cuales ya se ha llegado no se consideran) y se buscan los nodos conectados al root (valor 1 en la matriz). Se pushea cada valor al array **stack** y se eliminan de la matriz su simétrico ya que aquello implica que ya se considero dicho nodo. En la siguiente iteración del ciclo while, se saca de la stack el último elemento y se agrega su valor al array **nodesRemoved**, se recorren los nodos conectados a dicho nodo (ahora los nodos considerados en iteraciones previas ya no estan en la matriz) y aquellos en que su valor sea 1 se pushean a la stack y se modifican por 0 los nodos ubicados en la posición simétrica en la matriz. Se realiza todo lo anterior hasta que la matriz queda vacía.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwaldohidalgo%2Fcoding-interview-prep","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwaldohidalgo%2Fcoding-interview-prep","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwaldohidalgo%2Fcoding-interview-prep/lists"}