Enésimo dígito — Problema 400 de Leetcode

Dec 10 2022
Enlace del problema original: https://leetcode.com/problems/nth-digit/description/ En este problema, se nos pide encontrar el enésimo dígito de la secuencia infinita escrita como una cadena 1,2,3,4,5 ,6,7,8,9… Por ejemplo, el tercer dígito sería 3, pero el décimo dígito sería 1 (el lugar de las decenas de 10) y el 11 sería 0 (el lugar de las unidades de 10).

Enlace del problema original:https://leetcode.com/problems/nth-digit/description/

En este problema, se nos pide encontrar el enésimo dígito de la secuencia infinita escrita como una cadena 1,2,3,4,5,6,7,8,9…

Por ejemplo, el tercer dígito sería 3, pero el décimo dígito sería 1 (el lugar de las decenas de 10) y el 11 sería 0 (el lugar de las unidades de 10).

Antes de llegar a las explicaciones, el enfoque rápido que supera el 100% de las presentaciones es este, pero tenemos que usar un poco de matemáticas:

class Solution {
    public int findNthDigit(int n) {
        if (n < 10) {
            return n;
        }
        long numOfDigits = 0;
        long power = 1;
        while (numOfDigits + (9 * (long)Math.pow(10, power - 1) * power) <= n) {
            numOfDigits += (9 * (long)Math.pow(10, power - 1) * power);
            power++;
        }
        long quotient = (n - numOfDigits) / power;
        long mod = (n - numOfDigits) % power;
        long i = mod == 0 ? (quotient + (long)Math.pow(10, power - 1) - 1) : (quotient + (long)Math.pow(10, power - 1));
        String num = String.valueOf(i);
        return mod == 0 ? Character.digit(num.charAt(num.length() - 1), 10) : Character.digit(num.charAt((int)mod - 1), 10);
    }
}

Así que cambié para recorrer y calcular el número correcto del que sería el enésimo dígito, así:

class Solution {
    public int findNthDigit(int n) {
        int i = 0;
        int prevIndex = 0;
        int index = 0;
        while (index < n) {
            i++;
            String num = String.valueOf(i);
            prevIndex = index;
            index += num.length();
        }
        String str = String.valueOf(i);
        return Character.digit(str.charAt(n - prevIndex - 1), 10);
    }
}

La forma de hacerlo más rápido y aceptarlo fue hacer que la solución sea O(log n) encontrando un patrón para cuántos dígitos generó cada rango numérico, de la siguiente manera

Single digits 1-9 => 9 * 10^0 * 1 digits
Double digits 10-99 => 9 * 10^1 * 2 digits
...so the general formula is 9 * 10^(m - 1) * m digits for each number range

class Solution {
    public int findNthDigit(int n) {
        if (n < 10) {
            return n;
        }
        long numOfDigits = 0;
        long power = 1;
        while (numOfDigits + (9 * (long)Math.pow(10, power - 1) * power) <= n) {
            numOfDigits += (9 * (long)Math.pow(10, power - 1) * power);
            power++;
        }
        long quotient = (n - numOfDigits) / power;
        long mod = (n - numOfDigits) % power;
        long i = mod == 0 ? (quotient + (long)Math.pow(10, power - 1) - 1) : (quotient + (long)Math.pow(10, power - 1));
        String num = String.valueOf(i);
        return mod == 0 ? Character.digit(num.charAt(num.length() - 1), 10) : Character.digit(num.charAt((int)mod - 1), 10);
    }
}