16 |
17 | ### Primer alternativa
18 | ```javascript
19 | const binaryToDecimal = (binary) => {
20 | let sum = 0;
21 | for (let i = 0; i < binary.length; i += 1) {
22 | sum += Math.pow(2, binary.length - (i+1)) * binary[i];
23 | }
24 | return sum;
25 | };
26 | ```
27 |
28 | ### Segunda alternativa
29 | En este caso, se propone una **solución recursiva**.
30 | ```javascript
31 | const binaryToDecimalRec = (binary) => {
32 | const sum = Math.pow(2, binary.length - 1) * binary[0]
33 | if (binary.length !== 1) {
34 | return sum + binaryToDecimalRec(binary.slice(1));
35 | }
36 | return sum
37 | }
38 | ```
39 |
40 | ## Código
41 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/KBgB/4).
42 |
--------------------------------------------------------------------------------
/Ejercicios/Tests/test/14-SpyOn.spec.js:
--------------------------------------------------------------------------------
1 | const { expect } = require("chai");
2 | const spy = require("../Ejercicios/14-SpyOn/SpyOn");
3 | const adder = (n1, n2) => {
4 | return n1 + n2;
5 | };
6 | const adderSpy = spy(adder);
7 |
8 | describe("¿Es espia o no?", function () {
9 | it("debe retornar true", function () {
10 | expect(adderSpy.wasCalledWith(2)).toBe(true);
11 | });
12 | it("debe retornar true", function () {
13 | expect(adderSpy.returned(6)).toBe(true);
14 | });
15 | it("debe retornar false", function () {
16 | expect(adderSpy.wasCalledWith(0)).toBe(false);
17 | });
18 | it("debe retornar false", function () {
19 | expect(adderSpy.returned(9)).toBe(false);
20 | });
21 | it("debe retornar un numero", function () {
22 | expect(adderSpy.getCallCount()).to.equal(0);
23 | });
24 | it("debe retornar un numero", function () {
25 | expect(adderSpy(2, 4)).to.equal(6);
26 | });
27 | it("debe retornar un numero", function () {
28 | expect(adderSpy.getCallCount()).to.equal(1);
29 | });
30 | it("debe retornar un numero", function () {
31 | expect(adderSpy(3, 5)).to.equal(8);
32 | });
33 | it("debe retornar un numero", function () {
34 | expect(adderSpy.getCallCount()).to.equal(2);
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/Ejercicios/Tests/problems/minStack.js:
--------------------------------------------------------------------------------
1 | // Un stack o Pila es LIFO (last in first out),
2 | // osea el ultimo que entro es el primeor en salir.
3 | // Necesitas implementar un stack que tenga los siguientes métodos:
4 | // - push(value) // para añadir elementos
5 | // - pop() // para sacar un elemento
6 | // - min () // ver el elemento con el valor minimo Todas estas funciones tienen que correr en 0(1)
7 | // No se puede usar ningún array method
8 | // Idea: Tener una estructura separada para guardar el minimo
9 | // de cada nodo que se agrega,
10 | // y cuando sacamos el nodo removemos ese minimo.
11 |
12 | //dos clases, una con metodos pop,push,min
13 |
14 | class Node {
15 | constructor(value) {
16 | this.valor = value;
17 | this.next = null;
18 | }
19 | }
20 |
21 | class Stack {
22 | constructor(){
23 | this.primero = null;
24 | }
25 |
26 | push(elemento) {
27 | if(!this.primero){
28 | this.primero = new Node (elemento);
29 | }
30 |
31 | else {
32 | const nuevoNodo = new Node(elemento);
33 | nuevoNodo.next = this.primero;
34 | this.primero = nuevoNodo;
35 | }
36 | }
37 |
38 | pop() {
39 | const primeroSalir = this.primero;
40 | this.primero = primeroSalir && primeroSalir.next;
41 | return primeroSalir && primeroSalir.valor;
42 | }
43 |
44 | min(){
45 | return this.primero && this.primero.valor;
46 | }
47 | }
48 |
49 |
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Entrevistas Técnicas
3 |
4 |
5 |
6 |
Te preparamos para ingresar al mundo laboral brindándote las herramientas necesarias para conseguir un trabajo.
7 |
Estos ejercicios te van a ayudar a prepararte para futuras entrevistas tecnicas , aprender o repasar conceptos y como encararlos. Son ejercicios de entrevistas reales.
29 |
--------------------------------------------------------------------------------
/Ejercicios/11-ClockMinuteAdder/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Clock minute adder
4 | ## Introducción
5 | Dada una hora en string en **formato HH:MM**, y un número de minutos.
6 | Devolver la nueva hora pasados esos minutos.
7 |
8 | ##### IMPORTANTE
9 | El reloj es de 12 horas y tiene que devolverse en el formato HH:MM. Recuerda que no existen las 00hs.
10 |
11 | ##### Ejemplos:
12 | clockMinuteAdder (**'09:00', 20**);
13 | **ouput**: '09:20'
14 |
15 | clockMinuteAdder (**'01:30', 30**);
16 | **ouput**: '02:00'
17 |
18 | clockMinuteAdder (**'12:05', 100**);
19 | **ouput**: '01:45'
20 |
21 | ## Solución
22 | ```javascript
23 | const clockMinuteAdder = (time, minutesToAdd) => {
24 | // Separo las horas y los minutos
25 | const [hours, minutes] = time.split(':');
26 |
27 | // agrego el total de minutos y el total de horas
28 | const totalMinutes = (minutesToAdd + parseInt(minutes));
29 | const totalHours = Math.floor(totalMinutes/60) + parseInt(hours);
30 |
31 | // saco las nuevas horas y minutos
32 | const newHours = ((totalHours - 1) % 12) + 1 ; // para que no quede 0hrs
33 | const newMinutes = totalMinutes % 60;
34 |
35 | // le agrego formato de ceros adelante si es necesario
36 | const formatHours = newHours > 9 ? newHours : `0${newHours}`;
37 | const formatMinutes = newMinutes > 9 ? newMinutes : `0${newMinutes}`;
38 |
39 | //devuelvo la nueva hora
40 | return `${formatHours}:${formatMinutes}`;
41 | };
42 | ```
43 |
44 | ## Código
45 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/KEvy/3).
46 |
--------------------------------------------------------------------------------
/Ejercicios/Tests/test/05-minStack.spec.js:
--------------------------------------------------------------------------------
1 | const { expect } = require("chai");
2 | const minStack = require("../05-Ejercicios/MinStack");
3 |
4 | describe("minStack", function () {
5 | it("Chequeamos la clase constructora", () => {
6 | const minStack = new MinStack();
7 | expect(minStack).toHaveBeenCalledTimes(new Node());
8 | });
9 | it("pushes, pops, and peaks", () => {
10 | const minStack = new MinStack();
11 |
12 | minStack.push(4);
13 | minStack.push(1);
14 | minStack.push(1000);
15 |
16 | Test.assertEquals(minStack.peak(), 1000, "peak fails");
17 | Test.assertEquals(minStack.pop(), 1000, "pop fails");
18 | Test.assertEquals(minStack.peak(), 1, "peak fails");
19 | Test.assertEquals(minStack.pop(), 1, "pop fails");
20 | Test.assertEquals(minStack.peak(), 4, "peak fails");
21 | Test.assertEquals(minStack.pop(), 4, "pop fails");
22 | });
23 |
24 | it("mins!", () => {
25 | const minStack = new MinStack();
26 |
27 | minStack.push(4);
28 | minStack.push(1);
29 | minStack.push(1000);
30 | minStack.push(0.5);
31 | minStack.push(5000);
32 | minStack.push(0.1);
33 |
34 | Test.assertEquals(minStack.min(), 0.1, "min fails");
35 | minStack.pop();
36 | Test.assertEquals(minStack.min(), 0.5, "min fails");
37 | minStack.pop();
38 | Test.assertEquals(minStack.min(), 0.5, "min fails");
39 | minStack.pop();
40 | Test.assertEquals(minStack.min(), 1, "min fails");
41 | minStack.pop();
42 | Test.assertEquals(minStack.min(), 1, "min fails");
43 | minStack.pop();
44 | Test.assertEquals(minStack.min(), 4, "min fails");
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/Ejercicios/15-SpyOn/README.md:
--------------------------------------------------------------------------------
1 |
2 | # spyOn
3 | ## Introducción
4 | Implementa tu propia versión de la función **spyOn** que hace lo siguiente:
5 | - Toma una función como parámetro
6 | - Devuelve una función spy que toma cualquier numero de argumentos
7 | - spy llama a la función y devuelve lo que ella devuelve
8 | - spy tiene los siguientes métodos:
9 | - **.getCallCount()**: Devuelve la cantidad de veces que el spy fue llamado
10 | - **.wasCalledWith(val)**: devuelve true si la función fue alguna vez llamada con ese valor, else false
11 | - **.returned(val)**: devuelve true si alguna vez devolvió ese valor.
12 |
13 | #### Ejemplos:
14 | ```javascript
15 | function adder(n1, n2) { return n1 + n2; }
16 |
17 | const adderSpy = spyOn( adder );
18 |
19 | adderSpy.getCallCount(); // 0
20 |
21 | adderSpy(2, 4); // returns 6
22 | adderSpy.getCallCount(); // 1
23 |
24 | adderSpy(3, 5); // returns 8
25 | adderSpy.getCallCount(); // 2
26 | adderSpy.wasCalledWith(2); // true
27 | adderSpy.wasCalledWith(0); // false
28 | adderSpy.returned(6); // true
29 | adderSpy.returned(9); // false
30 | ```
31 |
32 | ## Solución
33 | ```javascript
34 | const spyOn = (fn) => {
35 | let callCount = 0;
36 | const calledWith = new Set();
37 | const returns = new Set();
38 | const spy = (...args) => {
39 | callCount += 1;
40 | args.forEach(arg => calledWith.add(arg));
41 | const result = fn(...args);
42 | returns.add(result);
43 | return result;
44 | }
45 | spy.getCallCount = () => callCount;
46 | spy.wasCalledWith = (val) => calledWith.has(val);
47 | spy.returned = (val) => returns.has(val);
48 | return spy;
49 | }
50 | ```
51 |
52 | ## Código
53 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/KUom).
54 |
--------------------------------------------------------------------------------
/Ejercicios/12-Intersection/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Intersection
3 | ## Introducción
4 | Dado dos arreglos **ordenados** devuelve un
5 | arreglo con los números que se repiten.
6 |
7 | #### Ejemplos:
8 | **input**: [1,3,5,7,10], [2,3,6,8,10,20]
9 | **output**: [3, 10]
10 |
11 | ## Solución
12 | ### Primer alternativa: Fuerza Bruta
13 | ```javascript
14 | function intersection(arr1, arr2) {
15 | const result = [];
16 | arr1.forEach(num1 => {
17 | arr2.forEach(num2 => {
18 | if(num1 === num2) result.push(num1);
19 | });
20 | });
21 | return result;
22 | }
23 | ```
24 | Complejidad Temporal | Complejidad Espacial
25 | --|--
26 | O(n*m)|O(n)
27 |
28 | ### Segunda alternativa: Solución Optima
29 | ```javascript
30 | function intersection2(arr1, arr2) {
31 | let index1 = 0;
32 | let index2= 0;
33 | const result = [];
34 | while(index1 < arr1.length && index2 < arr2.length) {
35 | if (arr1[index1] === arr2[index2]) {
36 | result.push(arr1[index1]);
37 | index1 += 1;
38 | index2 += 1;
39 | }
40 | else if(arr1[index1] < arr2[index2]) index1 += 1;
41 | else index2 += 1
42 | }
43 | return result;
44 | }
45 | ```
46 | Complejidad Temporal | Complejidad Espacial
47 | --|--
48 | O(n+m)|O(n)
49 |
50 |
51 | ###### Pero... ¿Qué pasaría si el arreglo no estuviese ordenado?
52 |
53 | ### Para un arreglo desordenado
54 | ```javascript
55 | function intersection3(arr1, arr2) {
56 | const hashMap = arr1.reduce((memo, num) => {
57 | memo[num] = true;
58 | return memo;
59 | }, {});
60 | return arr2.filter(num => hashMap[num]);
61 | }
62 | ```
63 | Complejidad Temporal | Complejidad Espacial
64 | --|--
65 | O(n+m)|O(n)
66 |
67 | Como verán, la complejidad espacial sigue siendo O(n) **pero estamos creando n de espacio extra por el HashMap**.
68 |
69 | ## Código
70 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/KKep/1).
71 |
--------------------------------------------------------------------------------
/Ejercicios/16-Curry/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Curry
3 | ## Introducción
4 | ¿Que es **currying**? Consiste en **transformar una función** que utiliza múltiples argumentos en una secuencia de funciones que utilizan un único argumento.
5 |
6 | #### Ejemplos
7 | ```javascript
8 | function calcAllFour(var1, var2, var3, var4) {
9 | return var1 + var2 - var3 * var4;
10 | }
11 | const curriedDoSomething = curry(calcAllFour); //argumentos -> []
12 | const firstReturn = curriedDoSomething(1); // argumentos -> [1]
13 | const secondReturn = firstReturn(2); // argumentos -> [1, 2]
14 | const thirdReturn = secondReturn(3); // argumentos -> [1, 2, 3]
15 | const fourthReturn = thirdReturn(4); // -9 -> (1 + 2 - 3 * 4)
16 | ```
17 |
18 | ## Solución
19 | ### En palabras
20 | Ahora haz el Curry:
21 | - Implementa la función "curry"
22 | - Mantén en mente
23 | - Tenés que saber cuantos argumentos la función que estas 'curring' toma.
24 | - La función anterior tenía 4 parámetros
25 | - La función que devuelvas del "curring" tiene acumuladas los argumentos anteriores.
26 | - La función debe determinar si los argumentos acumulados son iguales al numero de parámetros que la función original requiere, y devolver lo que la función original devolvería con los argumentos acumulados.
27 |
28 | ### Primer Alternativa: Solución ES5
29 | ```javascript
30 | function curry(fn) {
31 | return function curriedFn() {
32 | var args = [].slice.call(arguments);
33 | if (args.length >= fn.length) {
34 | return fn.apply(null, args);
35 | } else {
36 | return function resolver() {
37 | return curriedFn.apply(null, args.concat([].slice.call(arguments)));
38 | };
39 | }
40 | };
41 | };
42 | ```
43 |
44 | ### Segunda Alternativa: Solución ES6
45 | ```javascript
46 | const curry = (fn) => {
47 | return function curriedFn(...args) {
48 | if (args.length >= fn.length) return fn(...args);
49 | else return (...nextArgs) => curriedFn(...args, ...nextArgs);
50 | };
51 | };
52 | ```
53 |
54 | ## Código
55 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/KWvq/1).
56 |
--------------------------------------------------------------------------------
/Ejercicios/04-MultidimensionalSumArray/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Multi-Dimensional SumArray
3 | ## Introducción
4 | Ya trabajamos con arreglos de una unica dimension, ahora subiremos un escalón e iremos por arreglos de dos dimensiones, es decir, un arreglo de arreglos de enteros.
5 | En este caso, el objetivo es encontrar la suma de todos los elementos del arreglo.
6 |
7 | #### Ejemplos
8 | **mdArray**: [1,2,3,4]
9 | **output**: 10
10 |
11 | **mdArraySum**: [ [2,4] , [1], [4,2,1] ]
12 | **output**: 14
13 |
14 | **mdArraySum**: [ 2, [3,4], 5, [-3, [6 , [ 4,5 ] ] ] ]
15 | **output**: 26
16 |
17 | ## Solución
18 | ### En palabras
19 | Algunas consideraciones a tener en cuenta antes de implementar una solución.
20 |
21 | 1. La suma inicial es cero
22 | 2. Chequea cada elemento en el arreglo
23 | 1. Si no es un arreglo agrégalo a la suma
24 | 2. Si es un arreglo agrega la suma de todos sus elementos a la suma
25 | 3. Devuelve el total
26 |
27 | ### Primer Alternativa
28 | Podemos empezar a implementar la solución, pero antes tenemos que resolver una pregunta:
29 | ###### ¿Cómo podemos calcular la suma en los elementos de un sub-arreglo de un sub-arreglo? La respuesta es ***RECURSIÓN***
30 |
31 | ```javascript
32 | const mdArraySum = (arr) => {
33 | // Iniciamos la suma en 0
34 | let sum = 0;
35 | // Iteramos sobre el arreglo
36 | for (let i = 0; i < arr.length; i += 1) {
37 | // si es un arreglo le sumamos lo que devuelve llamar otra vez la función sobre ese arreglo
38 | if (Array.isArray(arr[i])) sum += mdArraySum(arr[i])
39 | // si no le sumamos al total
40 | else sum += arr[i]
41 | }
42 | // devolvemos el total
43 | return sum;
44 | }
45 | ```
46 | Considerando que **m es la cantidad de elementos en todos los arreglos** y **m el nivel máximo de profundidad** obtenemos los siguientes ordenes de complejidad.
47 |
48 | Complejidad Temporal | Complejidad Espacial
49 | --|--
50 | O(n)|O(m)
51 |
52 | ### Segunda alternativa
53 | Veamos una solución one-liner.
54 |
55 | ```javascript
56 | const mdArraySum2 = arr =>
57 | arr.reduce((total, elem) => total + (Array.isArray(elem) ? mdArraySum2(elem) : elem), 0)
58 | ```
59 |
60 | ## Código
61 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/Jl9b).
62 |
--------------------------------------------------------------------------------
/Ejercicios/03-MaxValue/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Max Value
4 | ## Introducción
5 | Se nos presenta un arreglo de enteros, estos representan el valor de una acción con el pasar del tiempo. ¿El objetivo del ejercicio? Encontrar cuál es la máxima ganancia posible de comprar a un horario y vender a otro después.
6 |
7 |
8 | #### Ejemplo
9 | **acciones**: [4, 3, 2, 5, 11]
10 | **mayor ganancia**: 9
11 |
12 | Esta ganancia la obtenemos comprando la acción cuando su valor es de 2 y vendiéndola cuando a 11.
13 |
14 | ## Solución
15 |
16 | ### Primer alternativa: Solución Fuerza Bruta
17 | ```javascript
18 | const maxValue = (stocks) => {
19 | // guardamos la primer diferencia
20 | let max = stocks[1] - stocks[0];
21 | // iteramos sobre cada posibilidad de compra
22 | for (let i = 0; i < stocks.length - 1; i += 1) {
23 | // e iteramos sobre cada posibilidad de venta
24 | for (let j = i + 1; j < stocks.length; j += 1){
25 | // sacamos ganancia potencial
26 | const potential = stocks[j] - stocks[i];
27 | // y deducimos si nos quedamos con el potencial o con el viejo máximo
28 | max = potential > max ? potential : max;
29 | }
30 | }
31 | // devolvemos el máximo
32 | return max;
33 | };
34 | ```
35 |
36 | Complejidad Temporal | Complejidad Espacial
37 | --|--
38 | O(n^2)|O(1)
39 |
40 |
41 | ### Segunda alternativa: Solución Optima
42 | ```javascript
43 | const maxValue2 = (stocks) => {
44 | // guardamos la primer diferencia
45 | let max = stocks[1] - stocks[0];
46 | // guardamos el precio mínimo hasta el momento
47 | let minPrice = stocks[0];
48 | // iteramos sobre las stocks
49 | for (let i = 1; i < stocks.length; i += 1) {
50 | // sacamos la ganacia potencial
51 | const potencial = stocks[i] - minPrice;
52 | // Nos quedamos con el mayor valor
53 | max = Math.max(max, potencial);
54 | // nos quedamos con el precio mínimo
55 | minPrice = Math.min(minPrice, stocks[i]);
56 | }
57 | // devolvemos el máximo
58 | return max;
59 | };
60 | ```
61 |
62 | Complejidad Temporal | Complejidad Espacial
63 | --|--
64 | O(n)|O(1)
65 |
66 | ## Código
67 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/JjYI).
68 |
--------------------------------------------------------------------------------
/Ejercicios/Tests/coverage/lcov.info:
--------------------------------------------------------------------------------
1 | TN:
2 | SF:/home/alemendoza/SoyHenry/reactoTesting/problems/bracketValidator.js
3 | FN:9,bracketValidator
4 | FNF:1
5 | FNH:1
6 | FNDA:4,bracketValidator
7 | DA:9,1
8 | DA:11,4
9 | DA:16,4
10 | DA:17,4
11 | DA:18,27
12 | DA:19,16
13 | DA:21,11
14 | DA:22,2
15 | DA:24,9
16 | DA:26,2
17 | LF:10
18 | LH:10
19 | BRDA:18,0,0,16
20 | BRDA:18,0,1,11
21 | BRDA:21,1,0,2
22 | BRDA:21,1,1,9
23 | BRF:4
24 | BRH:4
25 | end_of_record
26 | TN:
27 | SF:/home/alemendoza/SoyHenry/reactoTesting/problems/indexArray.js
28 | FN:15,findNeedle
29 | FNF:1
30 | FNH:1
31 | FNDA:2,findNeedle
32 | DA:15,1
33 | DA:17,2
34 | DA:19,18
35 | DA:22,24
36 | DA:24,7
37 | DA:28,1
38 | LF:6
39 | LH:6
40 | BRDA:22,0,0,17
41 | BRDA:22,0,1,7
42 | BRDA:24,1,0,1
43 | BRDA:24,1,1,6
44 | BRF:4
45 | BRH:4
46 | end_of_record
47 | TN:
48 | SF:/home/alemendoza/SoyHenry/reactoTesting/problems/mayorGanancia.js
49 | FN:5,mayorGanancia
50 | FNF:1
51 | FNH:1
52 | FNDA:2,mayorGanancia
53 | DA:5,1
54 | DA:6,2
55 | DA:7,2
56 | DA:8,8
57 | DA:9,20
58 | DA:11,20
59 | DA:12,8
60 | DA:17,2
61 | LF:8
62 | LH:8
63 | BRDA:11,0,0,8
64 | BRDA:11,0,1,12
65 | BRF:2
66 | BRH:2
67 | end_of_record
68 | TN:
69 | SF:/home/alemendoza/SoyHenry/reactoTesting/problems/minStack.js
70 | FN:15,(anonymous_0)
71 | FN:22,(anonymous_1)
72 | FN:26,(anonymous_2)
73 | FN:38,(anonymous_3)
74 | FN:44,(anonymous_4)
75 | FNF:5
76 | FNH:0
77 | FNDA:0,(anonymous_0)
78 | FNDA:0,(anonymous_1)
79 | FNDA:0,(anonymous_2)
80 | FNDA:0,(anonymous_3)
81 | FNDA:0,(anonymous_4)
82 | DA:16,0
83 | DA:17,0
84 | DA:23,0
85 | DA:27,0
86 | DA:28,0
87 | DA:32,0
88 | DA:33,0
89 | DA:34,0
90 | DA:39,0
91 | DA:40,0
92 | DA:41,0
93 | DA:45,0
94 | LF:12
95 | LH:0
96 | BRDA:27,0,0,0
97 | BRDA:27,0,1,0
98 | BRDA:40,1,0,0
99 | BRDA:40,1,1,0
100 | BRDA:41,2,0,0
101 | BRDA:41,2,1,0
102 | BRDA:45,3,0,0
103 | BRDA:45,3,1,0
104 | BRF:8
105 | BRH:0
106 | end_of_record
107 | TN:
108 | SF:/home/alemendoza/SoyHenry/reactoTesting/problems/multidimensionalArray.js
109 | FN:4,mDSumArray
110 | FNF:1
111 | FNH:1
112 | FNDA:10,mDSumArray
113 | DA:4,1
114 | DA:5,10
115 | DA:6,10
116 | DA:7,25
117 | DA:8,7
118 | DA:10,18
119 | DA:13,10
120 | LF:7
121 | LH:7
122 | BRDA:7,0,0,7
123 | BRDA:7,0,1,18
124 | BRF:2
125 | BRH:2
126 | end_of_record
127 |
--------------------------------------------------------------------------------
/Ejercicios/06-HasBalanceBrackets/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Has Balance Brackets
4 | ## Introducción
5 | Crear un bracket validator. La idea es que chequee que los brackets estén balanceados correctamente.
6 |
7 | Los brackets válidos son los siguientes: **[ ] ( ) { }**
8 |
9 | ### Ejemplos
10 |
11 | **input:** "{ [ ] ( ) }"
12 | **output:** true
13 |
14 | **input:** "{ [ ( ] ) }"
15 | **output:** false
16 |
17 | **input:** "{ [ }"
18 | **output:** false
19 |
20 | **input:** "{ [ ( [ { ( )[ ]{ } } ] ) ] }"
21 | **output:** true
22 |
23 | ## Solución
24 | ### En Palabras
25 |
26 | 1. Tienes:
27 | * **"opening"** - **( { [** - y,
28 | * **"closing"** - **) } ]** - brackets.
29 | 2. Cada closing bracket tiene que corresponder con la opening bracket mas cercano que empareje.
30 | 3. Cada opening y closing bracket tienen que estar en pareja.
31 |
32 | Entonces tienen que ir trackeando los opening brackets y fijarse si cuando encontramos una closing bracket, matchea con la opening bracket mas cercana
33 |
34 | ##### ¿Qué estructura de datos podemos utilizar para esto?
35 |
36 | ### Solución posible
37 | ```javascript
38 | const hasBalancedBrackets = (string) => {
39 | // Tenemos un diccionario para chequear las opening brackets con sus closing brackets
40 | const validBrackets = {
41 | '{' : '}',
42 | '[' : ']',
43 | '(' : ')',
44 | };
45 | // creamos un arreglo donde vamos a ir guardando los openBrackets
46 | const openBrackets = [];
47 | // iteramos sobre el string
48 | for (let i = 0; i < string.length; i += 1) {
49 | // si existe la propiedad significa que es un opening bracket entonces lo guardamos
50 | if (validBrackets[string[i]]) {
51 | openBrackets.push(string[i]);
52 | } else if (validBrackets[openBrackets.pop()] !== string[i]) {
53 | // Si no nos fijamos que el closing bracket corresponda con el ultimo opening bracket
54 | return false;
55 | }
56 | }
57 | // una vez que terminamos de recorrer
58 | // chequeamos que no haya quedado nada en el arreglo
59 | return !openBrackets.length;
60 | };
61 | ```
62 |
63 | ## Conclusión
64 | * Las estructuras de datos pueden ser muy útiles aunque... no estemos explícitamente creando una.
65 | * Podemos usar arreglos y métodos del arreglo para crear un arreglo que se comporte como un stack/queue
66 |
67 | ## Código
68 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/JsIz).
69 |
--------------------------------------------------------------------------------
/Ejercicios/Tests/coverage/lcov-report/block-navigation.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var jumpToCode = (function init() {
3 | // Classes of code we would like to highlight in the file view
4 | var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
5 |
6 | // Elements to highlight in the file listing view
7 | var fileListingElements = ['td.pct.low'];
8 |
9 | // We don't want to select elements that are direct descendants of another match
10 | var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
11 |
12 | // Selecter that finds elements on the page to which we can jump
13 | var selector =
14 | fileListingElements.join(', ') +
15 | ', ' +
16 | notSelector +
17 | missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
18 |
19 | // The NodeList of matching elements
20 | var missingCoverageElements = document.querySelectorAll(selector);
21 |
22 | var currentIndex;
23 |
24 | function toggleClass(index) {
25 | missingCoverageElements
26 | .item(currentIndex)
27 | .classList.remove('highlighted');
28 | missingCoverageElements.item(index).classList.add('highlighted');
29 | }
30 |
31 | function makeCurrent(index) {
32 | toggleClass(index);
33 | currentIndex = index;
34 | missingCoverageElements.item(index).scrollIntoView({
35 | behavior: 'smooth',
36 | block: 'center',
37 | inline: 'center'
38 | });
39 | }
40 |
41 | function goToPrevious() {
42 | var nextIndex = 0;
43 | if (typeof currentIndex !== 'number' || currentIndex === 0) {
44 | nextIndex = missingCoverageElements.length - 1;
45 | } else if (missingCoverageElements.length > 1) {
46 | nextIndex = currentIndex - 1;
47 | }
48 |
49 | makeCurrent(nextIndex);
50 | }
51 |
52 | function goToNext() {
53 | var nextIndex = 0;
54 |
55 | if (
56 | typeof currentIndex === 'number' &&
57 | currentIndex < missingCoverageElements.length - 1
58 | ) {
59 | nextIndex = currentIndex + 1;
60 | }
61 |
62 | makeCurrent(nextIndex);
63 | }
64 |
65 | return function jump(event) {
66 | switch (event.which) {
67 | case 78: // n
68 | case 74: // j
69 | goToNext();
70 | break;
71 | case 66: // b
72 | case 75: // k
73 | case 80: // p
74 | goToPrevious();
75 | break;
76 | }
77 | };
78 | })();
79 | window.addEventListener('keydown', jumpToCode);
80 |
--------------------------------------------------------------------------------
/Ejercicios/02-SumArray/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Sum Array
4 | ## Introducción
5 | En este caso se nos presentan dos elementos: una arreglo **ordenado** de números enteros y un número entero.
6 | El objetivo del ejercicio es encontrar si la combinación de dos números cualesquiera del arreglo, suman el número dado.
7 |
8 | #### Ejemplos
9 | ###### Existen dos valores
10 | **arreglo**: [2,4,5,9]
11 | **número**: 9
12 | **return**: true
13 |
14 | ###### No existen dos valores
15 | **arreglo**: [2,4,5,9]
16 | **número**: 12
17 | **return**: false
18 |
19 | ## Solución
20 | Como todo ejercicio, existen múltiples soluciones para un mismo problema.
21 | En este caso, analizáremos dos alternativas diferentes, luego determináremos cual es mejor.
22 |
23 | ### En palabras
24 | 1. Recorrer el arreglo con dos indices
25 | 2. Chequear si la suma de ambas posiciones da el valor pasado por parámetro
26 | 1. Si da, hemos terminado. Encontramos los valores buscados
27 | 2. Si no, seguimos avanzando
28 | 3. Si uno de los indices llego al final, hemos finalizado el recorrido y no existen dos valores en el arreglo que logren la suma esperada
29 |
30 | ### Primer alternativa: Solución naive
31 | ```javascript
32 | functionsumArray (arr, n) {
33 | // Itero sobre el arreglo
34 | for (let i = 0; i < arr.length - 1; i += 1) {
35 | // Itero sobre los números siguientes
36 | for (let j = i + 1; j < arr.length; j += 1) {
37 | // Veo si son iguales a la suma y devuelvo true
38 | if (arr[i] + arr[j] === n) return true;
39 | }
40 | }
41 | // Si termine de recorrer el arreglo devuelvo alse
42 | return false;
43 | }
44 | ```
45 |
46 | Complejidad Temporal | Complejidad Espacial
47 | --|--
48 | O(n^2)|O(1)
49 |
50 | ### Segunda alternativa: Mejor solución
51 | ```javascript
52 | function sumArray2 (arr, n) {
53 | // Creo un puntero para el principio y el final
54 | let start = 0;
55 | let end = arr.length - 1;
56 | // Mientras el puntero del principio sea menor al del final
57 | while (start < end) {
58 | // guardo el resultado de la suma
59 | const sum = arr[start] + arr[end];
60 | // Si son iguales devuelvo true
61 | if ( sum === n) return true;
62 | // Si es menor aumento el puntero de start
63 | else if (sum < n) start += 1;
64 | // Si es mayor decremento el puntero de end
65 | else end -= 1;
66 | }
67 | // Si salimos del for loop significa que no hay coincidencia
68 | return false;
69 | }
70 | ```
71 |
72 | Complejidad Temporal | Complejidad Espacial
73 | --|--
74 | O(n)|O(1)
75 |
76 | ## Código
77 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/Jh9N/0).
78 |
--------------------------------------------------------------------------------
/Ejercicios/01-FindNeedle/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Find Needle
4 | ## Introducción
5 | Encontrar el indice de la primera aparición de un string (needle) dentro de otro (haystack).
6 |
7 | Es decir, el objetivo del ejercicio es determinar si el primer string, needle, esta dentro del segundo, haystack, y en dicho caso, devolver el indice en el que esto ocurre.
8 |
9 | #### Ejemplos
10 | ###### Lo encuentra
11 | **needle**: redux
12 | **haystack**: react-redux
13 | **output**: 6
14 |
15 | ###### No lo encuentra
16 | **needle**: puntual
17 | **haystack**: pinky
18 | **output**: -1
19 |
20 | En este caso, como el needle no se encuentra en el haystack el valor de salida es -1.
21 |
22 | #### IMPORTANTE
23 | Para la resolución de este ejercicio no se puede utilizar la función preexistente: indexOf( )
24 |
25 |
26 | ## Solución
27 | ### En palabras
28 | 1. Visitar cada caracter del haystack
29 | 2. Visitar cada caracter del needle, si el primer caracter coincide:
30 | 1. Comparar el segundo caracter del needle con el siguiente del haystack
31 | 2. Continuar hasta llegar al final del needle o hasta que una comparación no sea igual
32 | 1. Si llegamos al final del needle es que encontramos el indice
33 | 3. Si el primer caracter del needle no coincide, avanzo al próximo caracter
34 | 4. Llegamos al final del haystack y no encontramos ninguna coincidencia
35 |
36 | ### Primer Alternativa
37 | Ahora si, busquemos la forma de traducir lo que ya dijimos en palabras a código.
38 | Ademas, debemos evaluar la complejidad en tiempo y espacio.
39 | ```javascript
40 | const findNeedle = (haystack, needle) => {
41 | // iteramos sobre el haystack
42 | for (let haystackIndex = 0; haystackIndex < haystack.length; haystackIndex += 1) {
43 | // comenzamos a iterar sobre el needle
44 | for (let needleIndex = 0; needleIndex < needle.length; needleIndex += 1 ) {
45 | // comparamos la letra del needle en la que estamos con la letra del haystack
46 | // cuando no hay match cortamos de comparar el needle
47 | if (haystack[haystackIndex + needleIndex] !== needle[needleIndex]) break;
48 | // si terminamos de recorrer la needle devolvemos el haystackIndex
49 | if (needleIndex + 1 === needle.length) return haystackIndex;
50 | }
51 | }
52 | // una vez que termina el loop y no encontramos match devolvemos -1
53 | return -1;
54 | }
55 | ```
56 | Considerando **haystack.length = n** y **needle.length = m**
57 |
58 | Complejidad temporal | Complejidad espacial
59 | --|--
60 | O(n*m)|O(1)
61 |
62 | ### Segunda Alternativa
63 | Otra forma de resolver el ejercicio, es utilizando la función slice.
64 |
65 | ```javascript
66 | function findNeedle2(haystack, needle){
67 | // iterar sobre el haystack
68 | for (let i = 0; i < haystack.length; i += 1) {
69 | // si la substring matchea el neddle podemos devoler el valor de i
70 | if (haystack.slice(i, i + needle.length) === needle) {
71 | return i;
72 | }
73 | }
74 | return -1;
75 | }
76 | ```
77 | Considerando **haystack.length = n** y **needle.length = m**
78 |
79 | Complejidad temporal | Complejidad espacial
80 | --|--
81 | O(n*m)|O(1)
82 |
83 |
84 | ## Código
85 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/Jc2b/0).
86 |
--------------------------------------------------------------------------------
/Ejercicios/05-MinStack/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Min Stack
4 | ## Introducción
5 | Para poder comprender el objetivo de esta actividad necesitamos saber **¿Qué es un stack?** Un stack, también conocido como pila es **LIFO** (Last-In First-Out), es decir, el último en entrar es el primero en salir.
6 |
7 | En este caso, el ejercicio es implementar un stack que tenga los siguientes métodos:
8 | 1. **push(value) :** añadir el elemento, value, al stack.
9 | 2. **pop ( ) :** sacar un elemento del stack.
10 | 3. **min ( ) :** obtener el elemento con el valor mínimo.
11 |
12 | #### Importante
13 | * **TODOS** los métodos mencionados anteriormente deben ser de O(1).
14 | * Para la resolución del ejercicio no se puede utilizar **ningún** *Array method*
15 |
16 | ## Solución
17 | ### En palabras
18 |
19 | 1. Implementar un stack normal
20 | 2. Luego, implementar un stack con un requisito mas > encontrar el mínimo
21 |
22 | ##### Importante
23 |
24 | **NO PUEDES** guardar el valor mínimo y cada vez que agregas un nuevo valor compararlo **¿POR QUÉ?**
25 | **( ! ) IDEA:** Tener una estructura separada para guardar el mínimo por cada nodo que se agrega, y cuando sacamos el nodo removemos ese mínimo
26 |
27 | ### Primer aproximación
28 | Una primer aproximación para la resolución de este ejercicio es realizar un stack común.
29 |
30 | ```javascript
31 | class Node{
32 | constructor(value) {
33 | this.value = value;
34 | this.next = null;
35 | }
36 | }
37 |
38 | class Stack{
39 | constructor(value) {
40 | this.top = null;
41 | }
42 |
43 | push(val) {
44 | if(!this.top) this.top = new Node(val);
45 | else {
46 | const newTop = new Node(val);
47 | newTop.next = this.top;
48 | this.top = newTop;
49 | }
50 | }
51 |
52 | pop() {
53 | const oldTop = this.top;
54 | this.top = oldTop && oldTop.next;
55 | return oldTop && oldTop.value;
56 | }
57 |
58 | peek() {
59 | return this.top && this.top.value
60 | }
61 | }
62 | ```
63 |
64 | ### Extendemos el stack
65 | Luego, mejoramos la resolución previamente presentada. Extendemos el stack para agregarle el mínimo
66 |
67 | ```javascript
68 | class MinStack extends Stack{
69 | constructor() {
70 | super();
71 | this.minimum = new Stack();
72 | }
73 |
74 | push(val) {
75 | if(!this.top) {
76 | this.top = new Node(val);
77 | this.minimum.push(val);
78 | }
79 | else {
80 | const newTop = new Node(val);
81 | newTop.next = this.top;
82 | this.top = newTop;
83 | if(this.minimum.peek() > val) this.minimum.push(val);
84 | else this.minimum.push(this.minimum.peek());
85 | }
86 | }
87 |
88 | pop() {
89 | const oldTop = this.top;
90 | this.top = oldTop && oldTop.next;
91 | this.minimum.pop();return oldTop && oldTop.value;
92 | }
93 |
94 | min() {
95 | return this.minimum.peek();
96 | }
97 | }
98 | ```
99 |
100 | ## Complejidad Espacial
101 | La complejidad espacial del ejercicio sigue siendo de O(n) con la diferencia que ahora almacenamos el doble de la información, O(2n)
102 |
103 | ## Código
104 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/JqWw).
105 |
--------------------------------------------------------------------------------
/Ejercicios/14-LongestIncreasingSubSequence/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Longest Increasing Subsequence
3 | ## Introducción
4 | Dado un arreglo de números, encontrá el length de la secuencia creciente mas larga posible. Esta secuencia puede saltear números en el arreglo.
5 |
6 | #### Ejemplos
7 | **input:** [3,10,4,5]
8 | La **secuencia es [3,4,5]**
9 | **output:** 3.
10 |
11 |
12 | longestIncreasingSubsequence(**[3, 4, 2, 1, 10, 6]**);
13 | Donde la **secuencia** es: 3, 4, 6
14 | **output**: 3
15 |
16 |
17 | longestIncreasingSubsequence(**[10, 22, 9, 33, 20, 50, 41, 60, 80]**);
18 | Donde la **secuencia** es: 10, 22, 33, 41, 60, 80 (or 10, 22, 33, 50, 60, 80)
19 | **output**: 6
20 |
21 | longestIncreasingSubsequence(**[10, 22, 9, 33, 20, 50, 41, 60, 80, 21, 23, 24, 25, 26, 27, 28]**);
22 | Donde, la **secuencia** es: 10, 20, 21, 23, 24, 25, 26, 27, 28
23 | **output**: 9
24 |
25 | ## Solución
26 | ### Primer Alterantiva: Fuerza Bruta
27 | Recorrer todas las posibilidades de subsecuencias y quedarse con la mas grande.
28 |
29 | ```javascript
30 | function IterativeLIS (nums) {
31 | const sequences = [[-Infinity]];
32 | nums.forEach(num => {
33 | const copySeq = [...sequences];
34 | copySeq.forEach(sequence => {
35 | if(sequence.slice(-1)[0] < num) sequences.push([...sequence, num]);
36 | });
37 | });
38 | return sequences.reduce((memo, seq) => {
39 | if (memo > seq.length) return memo;
40 | return seq.length;
41 | }, 1) -1;
42 | }
43 | ```
44 |
45 | Recorrer todas las posibilidades de subsecuencias incluyendo o no incluyendo ese número
46 | ```javascript
47 | function longestIncreasingSubsequence (nums, index = 0, base = -Infinity) {
48 | // si ya recorrimos todo el arreglo devolver cero ya que termino la secuencia
49 | if (index === nums.length) return 0;
50 | // sacar la longitud de la secuencia que llego cuando le numero es excluido
51 | const whenExcluded = longestIncreasingSubsequence(nums, index + 1, base);
52 | // fijarse si el numero es menor que el numero que llega en la base
53 | // si es menor directamente devolver el excluido
54 | if (nums[index] <= base) return whenExcluded;
55 | // Tomar el valor cuando es incluido en la secuencia sumandole uno por si mismo
56 | const whenIncluded = 1 + longestIncreasingSubsequence(nums, index + 1, nums[index]);
57 | // devolver el mayor entre el incluido y el no incluido
58 | return Math.max(whenIncluded, whenExcluded);
59 | }
60 | ```
61 |
62 | #### Complejidad Temporal
63 | La complejidad de tiempo de esta solución es **O(2^n)**.
64 |
65 | Pero, siempre que tomamos el **whenIncluded** de un elemento ese valor es siempre el mismo... ¿Por qué no lo guardamos? **Memoization FTW**
66 |
67 | ### Segunda Alternativa: Solución con Memoization
68 | ```javascript
69 | function memoLis (nums, index = 0, base = -Infinity, memo = {}) {
70 | if (index === nums.length) return 0;
71 | const whenExcluded = memoLis(nums, index + 1, base, memo);
72 | if (nums[index] <= base) return whenExcluded;
73 | let whenIncluded;
74 | if(memo.hasOwnProperty(index)) whenIncluded = memo[index]
75 | else {
76 | whenIncluded = 1 + memoLis(nums, index + 1, nums[index], memo);
77 | memo[index] = whenIncluded;
78 | }
79 | return Math.max(whenIncluded, whenExcluded);
80 | }
81 | ```
82 | Fijense que **solo guardamos el whenIncluded**, ya que en el excluido la base puede ser distinta y dar distintos resultados.
83 |
84 | #### Complejidad Temporal
85 | En este caso, la complejidad temporal es de **O(n^2)**. ¿Por qué? Porque por cada elemento recorremos solo una vez en todos los elementos.
86 |
87 | ## Código
88 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/KOFI/4).
89 |
--------------------------------------------------------------------------------
/Ejercicios/07-SolveGraph/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Solve Graph
4 | ## Introducción
5 | Un grafo/graph es un set de vertices conectados entre ellos por aristas.
6 |
7 | ### Undirected vs. Directed Graphs
8 |
9 |
10 |
11 |
12 | ### ¿Qué hay que hacer?
13 | Escribe una función que determine si existe un path entre dos vertices de un graph.
14 |
15 | El graph será representado como un objeto. Cada key representa un vértice. El valor, todos los vertices que pueden ser alcanzados.
16 |
17 | El graph, será un *'directed graph'*.
18 |
19 |
20 |
21 | Como observamos, en la imagen de la izquierda el nodo 'a' se conecta con el nodo 'b', el nodo 'b' con el nodo 'c' y 'd' y por último, el nodo 'c' con el nodo 'd'.
22 |
23 | ## Solución
24 | ### En palabras
25 | - La solución puede ser un algoritmo **Breadth-First** o **Depth-First**
26 | - Pero... los graphs pueden ser cíclicos
27 | - Si empezamos recorriendo el vértice A, eventualmente vamos a llegar al vértice R que apunta devuelta al A.
28 |
29 | ```javascript
30 | {
31 | a: ['c'],
32 | c: ['s', 'r'],
33 | r: ['a'],
34 | s: [ ]
35 | }
36 | ```
37 | - ¿El problema? Un algoritmo normal de BFS/DFS terminaría en un **loop infinito**.
38 | - Por lo tanto, tu algoritmo tiene que traquear todos los vertices que visitó
39 | - Si un vértice ha sido visitado sabemos que no tenemos que recorrer sus aristas por segunda vez
40 | - El **algoritmo se completa** cuando se ha encontrado el target o cuando todas las posibilidades fueron recorridas.
41 |
42 | ### Solución depth-first
43 |
44 | ```javascript
45 | const graph = {
46 | a: ['c'],
47 | b: ['c'],
48 | c: ['s', 'r'],
49 | d: ['a'],
50 | s: ['a', 'c'],
51 | r: ['d'],
52 | z: ['z']
53 | };
54 | function solveGraphDFS(graph, start, end, visited = {}) {
55 | // nos fijamos si ya visitamos este vértice
56 | if (visited[start]) return false;
57 | // lo agregamos a los visitados
58 | visited[start] = true;
59 | // iteramos sobre el arreglo de vértices
60 | for (let i = 0; i < graph[start].length; i += 1) {
61 | // Si encontramos el target devolvemos true
62 | if (end === graph[start][i]) return true;
63 | // si no llamamos recursivamente a la función para ver si sus aristas están conectadas
64 | else if (solveGraphDFS(graph, graph[start][i], end, visited)) return true
65 | }
66 | // si no devolvemos false
67 | return false;
68 | }
69 |
70 | solveGraphDFS(graph, 'a', 'r') // true
71 | solveGraphDFS(graph, 's', 'b') // false
72 | ```
73 |
74 | Complejidad Temporal | Complejidad Espacial
75 | --|--
76 | O(n)|O(n)
77 |
78 |
79 | ### Solución breadth-first approach
80 | ```javascript
81 | const graph = {
82 | a: ['c'],
83 | b: ['c'],
84 | c: ['s', 'r'],
85 | d: ['a'],
86 | s: ['a', 'c'],
87 | r: ['d'],
88 | z: ['z']
89 | };
90 | function solveGraphBFS(graph, start, end, visited = {}, queue = []) {
91 | // nos fijamos si ya visitamos este vértice
92 | if (visited[start]) return false;
93 | // lo agregamos a los visitados
94 | visited[start] = true;
95 | // iteramos sobre el arreglo de vértices
96 | for (let i = 0; i < graph[start].length; i += 1) {
97 | // agregamos todas sus conexiones al queue
98 | queue.push(graph[start][i]);
99 | }
100 | // comparamos si el siguiente del queue es nuestro target
101 | // sino llamamos recursivamente a la función con el start del siguiente del queue
102 | return queue[0] === end || solveGraphBFS(graph, queue.shift(), end, visited, queue);
103 | }
104 | solveGraphBFS(graph, 'a', 'r'); // true
105 | solveGraphBFS(graph, 's', 'b'); // false
106 | ```
107 | Complejidad Temporal | Complejidad Espacial
108 | --|--
109 | O(n)|O(n)
110 |
111 | ## Código
112 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/JuS9).
113 |
--------------------------------------------------------------------------------
/Ejercicios/Tests/coverage/clover.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/Ejercicios/08-FindWordStartingWith/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Find Word Starting With
4 | ## Introducción
5 | Dado un "libro" y un string para buscar, devolver todos los indices donde la palabra empieza con ese string.
6 |
7 | El libro vendrá con dos cosas: un id y un texto. **La búsqueda tiene que ser case insensitive.**
8 |
9 | #### Ejemplo
10 | ```javascript
11 | const book = {
12 | id: 1,
13 | text: 'Erase una vez un libro de palabras que era un poco aburrido pero tenia muchas'
14 | }
15 | ```
16 |
17 | findWordsStartingWith **(book, 'de')**
18 | **output:** [23]
19 |
20 | findWordsStartingWith **(book, 'un')**
21 | **output:** [ 6, 14, 43]
22 |
23 |
24 | ## Solución
25 | ### Primer alternativa
26 | Una alternativa, **naive**, es iterar a través del texto.
27 | ```javascript
28 | const findWordsStartingWithNaive = (book, query) => {
29 | const separators = {
30 | ' ': true,
31 | '.': true,
32 | ',': true,
33 | }
34 | const text = book.text.toLowerCase();
35 | const finds = [];
36 | for (let i = 0; i < text.length; i += 1) {
37 | if (i !== 0 && !separators[text[i-1]]) continue;
38 | for (let j = 0; j < query.length; j += 1) {
39 | if (query[j] !== text[i + j]) {
40 | i += j;
41 | break;
42 | }
43 | if (j === query.length - 1){
44 | finds.push(i);
45 | i += j;
46 | }
47 | }
48 | }
49 | return finds;
50 | }
51 | ```
52 | **Complejidad temporal:** O(n)
53 |
54 | ### Segunda Alternativa
55 | Otra alternativa, es utilizar un **trie**. Pero ... ¿Que es un trie?
56 |
57 | #### Ejemplo
58 | ```javascript
59 | {
60 | [char]: {
61 | data: data,
62 | [nextChar]: {
63 | data: data,
64 | // ...
65 | }
66 | }
67 | }
68 | ```
69 | ###### ¿Podes encontrar el mensaje secreto?
70 |
71 | ```javascript
72 | const trie = {
73 | t: {
74 | indexes: [0, 5],
75 | o: {
76 | indexes:[0, 5],
77 | n: {
78 | indexes: [0, 5],
79 | i: {
80 | indexes: [0]
81 | },
82 | t: {
83 | indexes: [5],
84 | o:{
85 | indexes: [5]
86 | }
87 | }
88 | }
89 | }
90 | }
91 | }
92 | ```
93 | ###### Equivale a:
94 | ```javascript
95 | buildTrie('Toni tonto')
96 | ```
97 |
98 | #### ¿Por qué?
99 | Porque **repetir la ejecución va a ser mucho mas rápido con un árbol**.
100 |
101 |
102 | ### Paso 1: Haz el TRIE
103 | ```javascript
104 | const buildTrie = (text) => {
105 | const trie = {};
106 | const separators = {
107 | ' ': true,
108 | '.': true,
109 | ',': true,
110 | }
111 | for (let i = 0; i < text.length; i += 1) {
112 | let currentLetter = trie;
113 | const startingIndex = i;
114 | while(text[i] && !separators[text[i]]) {
115 | currentLetter[text[i]] = currentLetter[text[i]] || { indexes: [] }
116 | currentLetter = currentLetter[text[i]];
117 | currentLetter.indexes.push(startingIndex);
118 | i++;
119 | }
120 | }
121 | return trie;
122 | };
123 | ```
124 | ### Paso 2:
125 | Una vez que el TRIE es creado todo lo que necesitas hacer es **iterar a través del largo del string**, **recorrer los nodos hasta** que llegues al **final** y luego, **retornar el arreglo de indices en ese punto**.
126 |
127 | ```javascript
128 | const tries = {};
129 | const findOrCreateTrie = ({ id, text }) => {
130 | tries[id] = tries[id] || buildTrie(text);
131 | return tries[id];
132 | };
133 |
134 | const findWordsStartingWith = (book, query) => {
135 | const trie = findOrCreateTrie(book)
136 | let currentLetter = trie;
137 | query = query.toLowerCase();
138 | for (let i = 0; i < query.length && currentLetter; i++) {
139 | currentLetter = currentLetter[query[i]]
140 | }
141 | return currentLetter ? currentLetter.indexes: [];
142 | }
143 | ```
144 |
145 | ## Complejidad
146 | ### Buscar si hay que construir el TRIE
147 | Complejidad Temporal | Complejidad Espacial
148 | --|--
149 | O(n+m)|O(1)
150 |
151 | ### Buscar si el TRIE ya fue construido
152 | Complejidad Temporal | Complejidad Espacial
153 | --|--
154 | O(m)|O(1
155 |
156 | ## Código
157 | Pueden encontrar las soluciones recién mencionadas en el siguiente [link](https://repl.it/JvdR/9).
158 |
--------------------------------------------------------------------------------
/Ejercicios/Tests/coverage/lcov-report/multidimensionalArray.js.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Code coverage report for multidimensionalArray.js
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
26 |
27 | - Visitar cada caracter del haystack
28 | - Si empieza con el primer
29 | - Comparar el segundo caracter del needle con elsiguiente del haystack
30 | - continuar hasta llegar al final del needle o hastaque una comparación no sea igual
31 | - Si llegamos al final del needle es qencontramos el indice
32 | - Si no empieza con el mismo caracter q la needleseguir al proximo caracter
33 | - Si llegamos al final del haystack no encontramos elmatch
34 |
35 |
36 |
37 | const findNeedle = (haystack, needle) => {
38 | // iteramos sobre el haystackfor
39 | (let haystackIndex = 0; haystackIndex < haystack.length; haystackIndex += 1) {
40 | // comenzamos a iterar sobre el needle
41 | for (let needleIndex = 0; needleIndex < needle.length; needleIndex += 1 ) {
42 | // comparamos la letra del needle en la que estamos con la letra del haystack
43 | // cuando no hay match cortamos de comparar el needle
44 | if (haystack[haystackIndex + needleIndex] !== needle[needleIndex]) break;
45 | // si terminamos de recorrer la needle devolvemos el haystackIndex
46 | if (needleIndex + 1 === needle.length) return haystackIndex;
47 | }
48 | }
49 | // una vez que termina el loop devolvemos -1
50 | return-1;
51 | }
52 |
53 |
54 |
55 |
56 | Complejidad de tiempo
57 |
???
58 |
59 |
60 | Complejidad de espacio
61 |
???
62 |
63 |
64 |
65 |
66 |
Solucion
67 |
68 | const findNeedle = (haystack, needle) => {
69 | // iteramos sobre el haystack
70 | for (let haystackIndex = 0; haystackIndex < haystack.length; haystackIndex += 1) {
71 | // comenzamos a iterar sobre el needle
72 | for (let needleIndex = 0; needleIndex < needle.length; needleIndex += 1 ) {
73 | // comparamos la letra del needle en la que estamos con la letra del haystack
74 | // cuando no hay match cortamos de comparar el needle
75 | if (haystack[haystackIndex + needleIndex] !== needle[needleIndex]) break;
76 | // si terminamos de recorrer la needle devolvemos el haystackIndex
77 | if (needleIndex + 1 === needle.length) return haystackIndex;
78 | }
79 | }
80 | // una vez que termina el loop devolvemos -1
81 | return-1;
82 | }
83 |
84 |
85 |
86 |
87 | Complejidad de tiempo
88 |
O(n*m)
89 |
90 |
91 | Complejidad de espacio
92 |
0(1)
93 |
94 |
95 |
96 |
97 |
98 |
Solucion
99 |
100 | const findNeedle = (haystack, needle) => {
101 | // iteramos sobre el haystack
102 | for (let haystackIndex = 0; haystackIndex < haystack.length; haystackIndex += 1) {
103 | // comenzamos a iterar sobre el needle
104 | for (let needleIndex = 0; needleIndex < needle.length; needleIndex += 1 ) {
105 | // comparamos la letra del needle en la que estamos con la letra del haystack
106 | // cuando no hay match cortamos de comparar el needle
107 | if (haystack[haystackIndex + needleIndex] !== needle[needleIndex]) break;
108 | // si terminamos de recorrer la needle devolvemos el haystackIndex
109 | if (needleIndex + 1 === needle.length) return haystackIndex;
110 | }
111 | }
112 | // una vez que termina el loop devolvemos -1
113 | return-1;
114 | }
115 |
116 |
117 |
118 |
119 | Complejidad de tiempo
120 |
O(n*m)
121 |
122 |
123 | Complejidad de espacio
124 |
0(1)
125 |
126 |
127 |
128 |
129 |
130 |
Solucion Alternativa
131 |
132 | function findNeedle2(haystack, needle){
133 | // iterar sobre el haystack
134 | for (let i = 0; i < haystack.length; i += 1) {
135 | // si la substring matchea el neddle podemos devoler el valor de i
136 | if (haystack.slice(i, i + needle.length) === needle) {
137 | return i;
138 | }
139 | }
140 | return-1;
141 | }
142 |
143 |
144 |
145 |
146 | Complejidad de tiempo
147 |
???
148 |
149 |
150 | Complejidad de espacio
151 |
???
152 |
153 |
154 |
155 |
156 |
157 |
Solucion Alternativa
158 |
159 | function findNeedle2(haystack, needle){
160 | // iterar sobre el haystack
161 | for (let i = 0; i < haystack.length; i += 1) {
162 | // si la substring matchea el neddle podemos devoler el valor de i
163 | if (haystack.slice(i, i + needle.length) === needle) {
164 | return i;
165 | }
166 | }
167 | return-1;
168 | }
169 |
//encontrar el indice de la primera aparicion de un string(needle)
120 | //dentro de otro(haystack)
121 | //no se puede utilizar indexOf()
122 |
123 | //ejemplo:
124 | //haystack = 'react-redux'
125 | //needle = 'redux'
126 | //output = 5
127 |
128 | //haystack = 'react-redux'
129 | //needle = 'hola'
130 | //output = -1
131 |
132 |
133 | module.exports = function findNeedle(haystack, needle) {
134 | // iteramos sobre el haystack
135 | for (let haystackIndex = 0; haystackIndex < haystack.length; haystackIndex += 1) {
136 | // comenzamos a iterar sobre el needle
137 | for (let needleIndex = 0; needleIndex < needle.length; needleIndex += 1 ) {
138 | // comparamos la letra del needle en la que estamos con la letra del haystack
139 | // cuando no hay match cortamos de comparar el needle
140 | if (haystack[haystackIndex + needleIndex] !== needle[needleIndex]) break;
141 | // si terminamos de recorrer la needle devolvemos el haystackIndex
142 | if (needleIndex + 1 === needle.length) return haystackIndex;
143 | }
144 | }
145 | // una vez que termina el loop devolvemos -1
146 | return -1;
147 | }
148 |
149 |