[LeetCode] -Matemáticas-1

prefacio

Registre los problemas relacionados con las matemáticas encontrados en las preguntas de cepillado de LeetCode, la primera parte

204. Contar números primos

Los números primos son una parte muy importante de la teoría de números y deberían ser el primer punto de conocimiento con el que la mayoría de las personas entren en contacto cuando entran en contacto por primera vez con la teoría de números. A continuación se muestra un resumen de varios métodos para juzgar números primos o detectar números primos según la solución oficial:

  1. El enfoque más original. La definición de número primo es que entre los números naturales mayores que 1, no hay otros números naturales excepto 1 y él mismo. Entonces, para cada número x, podemos enumerar cada número y en [2,x−1] de pequeño a grande y determinar si y es un factor de x. Siempre que una de las enumeraciones sea sí, significa que x es no es un numero primo.. Con este método, la complejidad temporal es O(n²) para determinar cuántos números primos hay entre n números. Una optimización de este método es que no es necesario juzgar [2,x−1], sino [2, x] [2,\sqrt{x}][ 2 ,X ] puede
  2. Tamiz de Ehrlich : Si x es un número primo, entonces los múltiplos de x 2x, 3x,... que son mayores que x no deben ser números primos, por lo que puedes recorrer cada número de pequeño a grande. Si este número es un número primo, marque todos sus múltiplos como números compuestos (excepto el número primo en sí). Este método también se puede optimizar: si x es un número primo, simplemente comience desde x * x y márquelo como un número compuesto , porque los números compuestos que comienzan desde 2x hasta x * x deben enumerarse como un número primo más pequeño que x. ya ha sido filtrado
  3. Tamiz lineal : en comparación con el tamiz de Ehrlich, durante la enumeración se mantiene un conjunto más de números primos obtenidos actualmente. A diferencia del tamiz de Ehrlich, el proceso de etiquetado de números compuestos ya no se realiza solo cuando x es un número primo , sino que se realiza para cada número entero x. Para el número entero x, ya no marcamos todos sus múltiplos, solo marcamos el número obtenido multiplicando el número en el conjunto de números primos con La etiqueta del producto de x es un número compuesto, y el proceso de etiquetado finaliza cuando se encuentra que x se puede dividir por un determinado número primo.

Así es como se hace una pantalla lineal:

public int countPrimes(int n) {
    
    
    List<Integer> primes = new ArrayList<Integer>(); //质数集合
    int[] isPrime = new int[n];                      //标记质数
    Arrays.fill(isPrime, 1);
    for (int i = 2; i < n; ++i) {
    
    
        if (isPrime[i] == 1) {
    
    
            primes.add(i);
        }
        //注意如果 i * primes.get(j) >= n 直接跳出循环
        for (int j = 0; j < primes.size() && i * primes.get(j) < n; ++j) {
    
    
            isPrime[i * primes.get(j)] = 0;
            //遇到能整除的质数结束标记过程
            if (i % primes.get(j) == 0) {
    
    
                break;
            }
        }
    }
    return primes.size();
}

326. Poder de 3

Según el rango de datos, el valor máximo de n no mayor que 2 31 - 1 es 3 19 = 1162261467. Entonces si n es la potencia de 3, es decir, n = 3 x , entonces n * 3 k = 3 19 debe Estar satisfecho , donde 0 <= k <= 19, es decir, 3 19 % n = 0, por lo que solo necesita juzgar si esta ecuación es verdadera. También determine si n es mayor que 0:

public boolean isPowerOfThree(int n) {
    
    
    return n > 0 && 1162261467 % n == 0;
}

1262. La suma más grande divisible por tres

En el array restante, permanecer[0] registra la suma máxima de los elementos que han quedado divididos por tres, quedando 0; permanecer[[1] registra la suma máxima de los elementos que han dejado 1, después de dividir por tres; permanecer[ 2] registra la suma máxima de los elementos que se han dividido por tres, quedando 1 La suma más grande de elementos que deja 2 después de dividir por tres. Después de atravesar todos los elementos, permanecer [0] es la respuesta a esta pregunta

public int maxSumDivThree(int[] nums) {
    
    
    int len = nums.length;
    int[] remain = new int[3];
    int a,b,c;
    for(int i = 0; i < len; i++){
    
    
        a = remain[0] + nums[i];
        b = remain[1] + nums[i];
        c = remain[2] + nums[i];
        remain[a % 3] = Math.max(remain[a % 3], a);
        remain[b % 3] = Math.max(remain[b % 3], b);
        remain[c % 3] = Math.max(remain[c % 3], c);
    }
    return remain[0];
}

171. Número de serie de la columna de la tabla de Excel

Convertir una cadena de caracteres en un número equivale a convertir hexadecimal a decimal.
Pero no hay 0 en decimal, y 'A' corresponde a 1 en lugar de 0, por lo que al convertir letras en números, debe agregar uno, es decir, letra - 'A' + 1 en lugar de letra - 'A'

public int titleToNumber(String columnTitle) {
    
    
    int len = columnTitle.length();
    int ans = 0;
    for(int i = 0; i < len; i++){
    
    
        ans = ans * 26 + (columnTitle.charAt(i) - 'A' + 1);
    }
    return ans;
}

168. Nombres de columnas de la tabla de Excel

Simplemente invierta la idea de la pregunta 171. Al principio, hice 168 preguntas sin hacer 171 preguntas y no podía entender la oración "cn–". Luego hice la pregunta 171 primero, "columnTitle.charAt(i) - 'A' + 1" en 171 es bastante fácil de entender.

Después de restar cn uno cada vez, el resto de 26 se obtiene como " columnTitle.charAt(i) - 'A' " en 171, por lo que agregar 'A' es la letra en la posición correspondiente. Por analogía, todas las letras se conectan mediante StringBuilder. El orden de conexión es de menor a mayor; invierta de mayor a menor.

public String convertToTitle(int cn) {
    
    
    StringBuilder sb = new StringBuilder();
    while (cn > 0) {
    
    
        cn--;
        sb.append((char)(cn % 26 + 'A'));
        cn /= 26;
    }
    return sb.reverse().toString();
}

292. Juego de Nim

Si quedan 0 piedras cuando es mi turno, entonces debo perder; si queda 1 piedra, entonces puedo tomar 1 piedra; cuando es el turno del oponente y no hay piedras para tomar, el oponente debe perder; si quedan 2 piedras, entonces puedo Si tomo 2, si no quedan piedras en el turno del oponente, el oponente perderá; si quedan 3, entonces puedo tomar 3; si no quedan piedras en el Es el turno del oponente, el oponente perderá, si quedan 4, entonces no me importa si tomo 1, ya sean 2 o 3, las piedras restantes del otro lado las puedo tomar de una vez, si es mi turno nuevamente y Si no tengo piedras para tomar, perderé; si quedan 5, solo puedo tomar 1 y darle las 4 restantes al Enfrente, al igual que dejarme 4 a mí, el lado opuesto perderá... Puedes encontrar el patrón Si n toma el resto 4 como 0, entonces perderé.

public boolean canWinNim(int n) {
    
    
    return n % 4 != 0;
}

470. Implementar Rand10() usando Rand7()

randX() puede obtener [1,X], entonces randX() - 1 es [0,X - 1], (randX() - 1) * Y es [0,(X - 1)Y], luego (randX () - 1) * Y + randY() es [1,X*Y]

Por lo tanto, existen randX() y randY(), y randX*Y se puede obtener mediante (randX() - 1) * Y + randY()

Entonces, para esta pregunta, si hay rand7 al principio, podemos obtener rand49. Si el resultado está en [1,40], podemos tomar el resto 10 y agregar 1 para obtener rand10. Si el resultado está en [41,49], puedes restar 40 para obtener [1,9], que es rand9, al que puede seguir rand7 para obtener rand63. De la misma manera, si el resultado está en [1,60], puede obtener rand10; de lo contrario, obtiene rand3 y puede seguir a rand7 para obtener rand21. En este momento, si el resultado está en [1,20], puede obtener rand10; de lo contrario, solo queda un resultado, 1, y no puede continuar obteniendo nuevos rand y solo puede realizar un ciclo desde el principio.

public int rand10() {
    
    
    while(true) {
    
    
        int rand7_1 = rand7();
        int rand7_2 = rand7();
        int r1 = (rand7_1 - 1) * 7 + rand7_2; //rand 49
        if(r1 <= 40) return r1 % 10 + 1; //rand 10

        r1 -= 40; //rand 9
        int rand7_3 = rand7();
        int r2 = (r1 - 1) * 7 + rand7_3; //rand 63
        if(r2 <= 60) return r2 % 10 + 1; //rand 10

        r2 -= 10; //rand 3
        int rand7_4 = rand7();
        int r3 = (r2 - 1) * 7 + rand7_4; //rand 21
        if(r3 <= 20) return r3 % 10 + 1; 
        
        //此时r3 - 20是1,说明后续无法继续去找rand X*Y了,只能重新开始循环
    }
}

50. Potencia(x,n)

Para calcular x n , si seguimos la idea de multiplicar n x, la complejidad es O(n); mientras que el poder rápido se basa en la idea de divide y vencerás, x n será igual al cuadrado de x n/ 2 , entonces podemos calcular x n primero /2 y luego realizar una operación cuadrática para obtener x n . De la misma manera, x n/2 es igual a x n/4 . Por lo tanto, primero podemos calcular x n/4 y luego realice una operación cuadrada para obtener x n/2 , y así sucesivamente, por lo que la complejidad total es O (logn), lo que reduce el tiempo de cálculo.

Cabe señalar que si n es un número impar, entonces x n debe ser igual a x n/2 * x n/2 * x, por lo que es necesario determinar si es necesario multiplicar por uno más x al realizar la operación de raíz cuadrada.

class Solution {
    
    
    public double myPow(double x, int n) {
    
    
        return n >= 0 ? quickPow(x, n) : 1.0 / quickPow(x, -n);
    }
    public double quickPow(double x, long n) {
    
    
        if (n == 0) {
    
    
            return 1.0;
        }
        //计算平方根
        double tmp = quickPow(x,n / 2);
        return n % 2 == 0 ? tmp * tmp : tmp * tmp * x;
    }
}

Supongo que te gusta

Origin blog.csdn.net/Pacifica_/article/details/125566556
Recomendado
Clasificación