【LeetCode】 Una colección de preguntas numéricas feas

263. Números feos

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Ideas

  • En primer lugar, los números feos deben ser enteros positivos , por lo que n<1puedes devolver falso directamente;
  • Porque n >= 1, si n es divisible por 2/3/5, significa que son números feos.

código

class Solution {
    
    
public:
    bool isUgly(int n) {
    
    
        // ugly只能是正整数
        if(n < 1) return false;
        vector<int> factors = {
    
    2, 3, 5};
        for(int i=0; i<=2; ++i){
    
    
            while(n % factors[i] == 0){
    
    
                n /= factors[i];
            }
        }
        return n == 1;
    }
};

264. Número de Buey II

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Método 1: montón mínimo

Ideas

  • Para obtener el enésimo número feo, puede utilizar una implementación de montón mínimo .
  • El montón de inicialización está vacío y primero se agrega el número 1 más pequeño y feo. Cada vez que se elimina el elemento superior x del montón, x es el número feo más pequeño del montón. 2x, 3x y 5x también deben ser números feos, por lo que también se agregan al montón mínimo.
  • Sin embargo, el método anterior provocará elementos duplicados . Para evitar esta situación, utilice un conjunto de hash para eliminar duplicados y evitar agregar los mismos elementos al montón varias veces.
  • Cuando se excluyen los elementos duplicados, el enésimo elemento extraído del montón mínimo es el enésimo número feo.

código

class Solution {
    
    
public:
    int nthUglyNumber(int n) {
    
    
        vector<int> factor = {
    
    2, 3, 5};
        priority_queue<long, vector<long>, greater<long>> heap;
        unordered_set<long> s;
        // 先把丑数 1 加入
        s.insert(1L);
        heap.push(1L);
        long cur;
        for(int i=0; i<n; ++i){
    
    
            cur = heap.top();
            heap.pop();
            for(int f : factor){
    
    
                // 依次计算 2x 3x 5x
                long temp = cur * f;
                // s中没有temp 将其存入
                if(!s.count(temp)){
    
    
                    s.insert(temp);
                    heap.push(temp);
                }
            }
        }
        return (int)cur;
    }
};

Método 2: programación dinámica (método de tres punteros)

Ideas

  • El método 1 utiliza el montón mínimo, que almacenará números más feos por adelantado, y el proceso de mantener el montón mínimo también conduce a una gran complejidad temporal. Se pueden utilizar métodos de programación dinámica para la optimización.

  • Defina la matriz dp, donde dp [i] representa el i-ésimo número feo, luego dp [n] es la respuesta a esta pregunta. Entre ellos, dp[1] = 1.

  • Podemos calcular los números feos restantes mediante tres punteros p 2 , p 3 y p 5 . El significado de p i es la posición del número más payaso que puede multiplicarse por i. La calificación aquí se refiere a: Si un número feo nums[pi ] puede multiplicarse por i para obtener el siguiente número feo, entonces este número feo nums[pi ] nunca estará calificado para ser multiplicado por i. Ponemos p i + +, simplemente deja que nums[p i ] apunte al siguiente número feo.

  • Por ejemplo:

    Al principio, los únicos números feos son {1}. 1 se puede multiplicar por 2, 3 y 5, y el más pequeño 1 × 2 = 2 se suma a la secuencia numérica fea.

    Ahora hay {1, 2} en los números feos. En el paso anterior, 1 se ha multiplicado por 2, por lo que no es necesario comparar 1 × 2 en el futuro, por lo que se considera que 1 ha perdido la calificación para multiplicarse por 2.

    Ahora 1 está calificado para multiplicarse por 3 y 5, y 2 está calificado para multiplicarse por 2, 3 y 5, pero 2 × 3 y 2 × 5 son definitivamente mayores que 1 × 3 y 1 × 5, por lo que no hay hay que comparar. Entonces solo necesitamos comparar 1×3, 1×5, 2×2 .

    Por analogía, cada vez que comparamos los números más feos que están calificados para ser multiplicados por 2, 3 y 5, y seleccionamos el más pequeño como el siguiente número feo, supongamos que el número feo seleccionado es el mismo que i (i = 2 , 3, 5), por lo que pierde la calificación para multiplicarse por i. Simplemente coloque el p i ++ correspondiente y deje que p i apunte al siguiente número feo.

código

class Solution {
    
    
public:
    int nthUglyNumber(int n) {
    
    
        vector<int> dp(n+1);
        dp[1] = 1;
        int p2 = 1, p3 = 1, p5 = 1;
        for(int i=2; i<=n; ++i){
    
    
            int num2 = 2 * dp[p2];
            int num3 = 3 * dp[p3];
            int num5 = 5 * dp[p5];
            dp[i] = min(min(num2, num3), num5);
            // 确定dp[i]是由哪个数字生成的
            if(dp[i] == num2)   p2++;
            if(dp[i] == num3)   p3++;
            if(dp[i] == num5)   p5++;
        }
        return dp[n];
    }
};

1201. Feo Número III

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Método: búsqueda binaria + principio de inclusión-exclusión

Ideas

  • Lo primero que hay que tener en cuenta es que la definición de "número feo" en esta pregunta es diferente de las dos preguntas anteriores. El feo número x no se puede enumerar directamente aquí (método de tres punteros), porque x es demasiado grande y provocará un tiempo de espera.

  • Esta pregunta es una versión mejorada de 878. El enésimo número mágico . Cambia los dos números por tres números para hacerlo más difícil. En comparación con la pregunta 878, esta pregunta solo necesita modificar la función para encontrar el número de números feos menores o iguales a x, y la parte de búsqueda binaria es exactamente la misma. Se recomienda revisar primero la pregunta 878. El mapa conceptual para esta pregunta se adjunta a continuación.

    Insertar descripción de la imagen aquí

  • Los conjuntos formados por múltiplos de a, múltiplos de b y múltiplos de c menores o iguales que ∪B∪C∣ se pueden obtener a partir del principio de inclusión-exclusión :

    ∣A∪B∪C∣=∣A∣+∣B∣+∣C∣−∣A∩B∣−∣A∩C∣−∣B∩C∣+∣A∩B∩C∣

  • Por lo tanto, el número de números feos menores o iguales a x es: x/a + x/b + x/c - x/lcm_a_b - x/lcm_b_c - x/lcm_a_c + x/lcm_a_b_c. Puedes utilizar la función múltiplo de mínimo común std::lcm.

  • A continuación, mediante la búsqueda binaria , el límite se reduce continuamente hasta que el número correspondiente a una determinada posición contenga exactamente n factores numéricos feos.

código

class Solution {
    
    
public:
    using ll = long long;
    ll nthUglyNumber(ll n, ll a, ll b, ll c) {
    
    
        ll lcm_a_b = std::lcm(a, b), lcm_a_c = std::lcm(a, c), lcm_b_c = std::lcm(b, c);
        ll lcm_a_b_c= std::lcm(lcm_a_b, c);
        // 最小的丑数必然是a、b、c的最小值
        ll left = min(min(a, b), c);
        ll right = n * left;
        while(left + 1 < right){
    
    
            ll mid = (left + right) / 2;
            if(mid/a + mid/b + mid/c - mid/lcm_a_b - mid/lcm_a_c - mid/lcm_b_c + mid/lcm_a_b_c < n){
    
    
                left = mid;
            }
            else right = mid;
        }
        return right;
    }
};

313. Número súper feo

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Método: "Fusión de múltiples vías"

Ideas

  • Esta pregunta es en realidad 264. 丑数 IIun avance de. La primera usa tres punteros, correspondientes a 2, 3 y 5 respectivamente. Sin embargo, la longitud de la matriz de números primos en esta pregunta no es fija, por lo que se usa una matriz de punteros para corresponder a cada valor. de primos.

  • El primer número feo debe ser 1, y los "números feos generados en el futuro" se basan todos en "números feos existentes" (use "números feos existentes" multiplicados por los "factores primos dados" primos [i]). El proceso específico se muestra en la figura.

    Insertar descripción de la imagen aquí

    • Obviamente, debemos tomar el valor más pequeño cada vez, luego mover el puntero hacia atrás (apuntando al siguiente número feo) y repetir este proceso hasta encontrar el enésimo número feo.
    • Además, dado que cada uno de nuestros movimientos del puntero y la construcción de dp aumentan monótonamente , la deduplicación se puede lograr comparando con dp[i-1] sin hacer referencia a la estructura Set.

código

class Solution {
    
    
public:
    long nthSuperUglyNumber(int n, vector<int>& primes) {
    
    
        int len = primes.size();
        // 指针数组
        vector<long> ptr(len, 1);
        vector<long> dp(n+1, 0);
        dp[1] = 1;
        for(int i=2;i<=n;++i){
    
    
            int flag = 0;
            dp[i] = primes[0] * dp[ptr[0]];
            for(int j=0; j<len; ++j){
    
    
                long cur = primes[j] * dp[ptr[j]];
                if(cur < dp[i]){
    
    
                    flag = j;
                    dp[i]= cur;
                }     
            }
            ptr[flag]++;
            // 如果当前值和上一个丑数一样,那么跳过该丑数
            if(dp[i] == dp[i-1]) i--;
        
        }
        return dp[n];
    }
};

Resumir

  • Todas las preguntas anteriores son preguntas relacionadas con números feos. La definición de números feos no es fija, por lo que debe comprender cuidadosamente el significado de las preguntas antes de comenzar a calcular.
  • Porque 263. 丑数se puede resolver utilizando ideas matemáticas simples ;
  • Para , 264. 丑数IIse utilizan el montón mínimo y la programación dinámica (es decir, el método de tres punteros ) , pero el método del montón mínimo lleva más tiempo y el segundo método es más recomendado;
  • Porque 1201. 丑数III, a diferencia de la definición general de números feos, es una versión mejorada de 878, el enésimo número mágico , que utiliza búsqueda binaria y principios de inclusión-exclusión ;
  • Para 313.超级丑数, es una versión mejorada, se puede resolver 264. 丑数IIextendiendo el método de tres punteros a múltiples punteros , que también puede entenderse como un método de combinación multidireccional .

Referencias

  1. Solución oficial de Ugly Numbers II
  2. Cómo entender el método de tres puntos
  3. 313. Número súper feo: [Mitsuha Miyamizu] Una pregunta con dos soluciones: "Cola de prioridad" y "Fusión múltiple"

Supongo que te gusta

Origin blog.csdn.net/weixin_43894455/article/details/132129527
Recomendado
Clasificación