Roman to Integer en LeetCode: solución en PHP


Para tratar de mantenerme activo en LeetCode y para practicar un poco mi PHP decidí resolver este problema para convertir números romanos a números decimales, y después de algunos intentos que no cumplían los test llegué a esta solución que sí los pasó todos:


class Solution {

    /**
     * @param String $s
     * @return Integer
     */
    function romanToInt($s) {
        $_numbers = [
            'I' => 1,
            'V' => 5,
            'X' => 10,
            'L' => 50,
            'C' => 100,
            'D' => 500,
            'M' => 1000
        ];
        $total = 0;
        $prev = 0;

        foreach (str_split($s) as $c) {
            $current = $value = $_numbers[$c];
            if ($prev > 0 && $current > $prev) {
                $value = $current - 2 * $prev;
            }
            $total += $value;
            $prev = $current;
        }

        return $total;
    }
}

Solución correcta y el enfoque es el estándar para este problema.

Un comentario: $current = $value = $_numbers[$c] — asignas dos variables en una línea para luego pisar $value condicionalmente. Es válido pero ligeramente confuso; $current y $value arrancan iguales y eso no es obvio a primera lectura.

La lógica de $current - 2 * $prev es el truco interesante — explícame por qué el 2 *.

Hasta me sentí en examen, yo creo que piensa que le pedí ayuda a Gemini. Mi explicación fue la siguiente:

Al sumar siempre el valor actual y al encontrar que este valor actual es mayor al que se sumó en la iteración anterior, doy por hecho que ese valor anterior forma parte de un "número compuesto" con el valor actual, entonces tengo que obtener la diferencia del actual (que es mayor) y el anterior (que es menor) y dicha diferencia representa realmente el valor del "número compuesto"; pero como el número anterior menor ya se sumó al total en su propia iteración, debo quitarlo del valor real del "número compuesto" recién determinado.

Exacto. Es una forma elegante de no tener que hacer lookahead — lees hacia adelante implícitamente al detectar que el actual es mayor que el anterior. Big O: O(n) tiempo, O(1) espacio si ignoras el str_split que crea un array. Si lo cuentas, O(n) espacio. En una entrevista vale la pena mencionarlo.

Problema anterior

Comentarios