Coding Problem #2

Este problema fue preguntado por Uber

Dado un array de enteros, devuelve un array en el cada elemento en el índice i del nuevo array es el producto de todos los números en el array original excepto el del índice i


Por ejemplo, si tu entrada fue [1, 2, 3, 4, 5], la salida esperada sería [120, 60, 40, 30, 24]. Si tu entrada fue [3, 2, 1], la salida esperada sería [2, 3, 6].


Bonus: ¿qué pasa si no puedes usar la división?


Solución: Intenta resolverlo antes de mirar la solución, a ver que se te ocurre.

Bueno, como siempre vamos a empezar analizando este problema por medio de TDD. Recuerda que propondré una solución, pero no tiene porque ser la mejor ni la más adecuada, recuerda que yo también estoy aprendiendo y practicando cada día :)


En unos 5 minutos hemos sacado la siguiente solución, extremadamente fea y desordenada, pero como tenemos nuestros tests podemos refactorizar, vamos a ello. Primero os dejo la solución por aquí, teniendo en cuenta que no hemos usado la división como nos dice el problema:


Los tests y la clase implementada:


@Test
public void givenAnArrayWithOneElementShouldReturnTheSameElement() {
    int[] array = new int[]{1};
    int[] arrayResult = Problem.productOfNumbers(array);

    assertArrayEquals(array, arrayResult);
}

@Test
public void givenAnArrayWithTwoElementsShouldReturnTheSameArray() {
    int[] array = new int[]{2, 3};
    int[] arrayResult = Problem.productOfNumbers(array);

    assertArrayEquals(array, arrayResult);
}

@Test
public void givenAnArrayWithThreeOrMoreElementsShouldReturnTheProductOfNumbers() {
    int[] array = new int[]{1, 2, 3, 4, 5};
    int[] arrayExpected = new int[]{120, 60, 40, 30, 24};
    int[] arrayResult = Problem.productOfNumbers(array);

    assertArrayEquals(arrayExpected, arrayResult);
}

public class Problem {

    public static int[] productOfNumbers(int[] numbers) {
        if (numbers.length < 3) return numbers;
        int result = 1;
        int[] arrayResult = new int[numbers.length];

        for (int i = 0; i < numbers.length; i++) {
            for(int j = 0; j < numbers.length; j++){
                if(j != i){
                    result *= numbers[j];
                }
            }
            arrayResult[i] = result;
            result = 1;
        }
        return arrayResult;
    }
}

Después de darle un par de vueltas se me ocurrió una solución en la que en cada iteración extrajéramos el número actual del array y multiplicamos el resto, para ello, he hecho uso de programación funcional, no soy un gran experto en esto, pero bueno es la mejor solución que se me ocurre, si se te ocurre alguna mejor o ves algún fallo en esta házmelo saber, estoy aprendiendo.


Ahora la refactorización:


public class Problem {
    
    public static int[] productOfNumbers(int[] numbers) {
        if (numbers.length < 3) return numbers;
        List<Integer> result = new ArrayList<>();

        Arrays.stream(numbers)
            .forEach(number -> {
                result.add(Arrays.stream(numbers)
                        .filter(n -> n != number)
                        .reduce((n1, n2) -> n1 * n2)
                        .getAsInt());
            });

        return result.stream().mapToInt(n -> n).toArray();
    }
}

Espero que te haya gustado este problema, nos vemos en el próximo, hasta la próxima :)


©2020 por Juanma Perez.