Notas de cepillado de Likou: 338. Recuento de bits (cuatro soluciones, método de fuerza bruta -> método de búsqueda de memoria -> método de programación dinámica, se recomienda encarecidamente la operación del cuarto bit, capa por capa, fácil de entender)

tema:

338. Recuento de bits
Dado un número entero no negativo. Para cada número i en el rango 0 ≤ i ≤ num, cuente el número de 1 en su número binario y devuélvalos como una matriz.

Ejemplo 1:

Entrada: 2
Salida: [0,1,1]

Ejemplo 2:

Entrada: 5
Salida: [0,1,1,2,1,2]

Avanzado:

Es muy fácil dar una solución con una complejidad de tiempo de O (n * sizeof (integer)). Pero, ¿puede hacerlo con un escaneo en tiempo lineal O (n)?
——————————————————————————————————
Se requiere que la complejidad espacial del algoritmo sea O (n).
——————————————————————————————————
¿Puede seguir mejorando la solución? Se requiere que no se utilicen funciones integradas (como __builtin_popcount en C ++) en C ++ o cualquier otro lenguaje para realizar esta operación.

Método 1: violencia

Idea para la solución del problema:
Esta debería ser la forma más fácil de pensar, atravesar cada número de 0 a num y contar el número de unos en el binario de cada número.

Complejidad: Complejidad
temporal: O (N * sizeof (int))
Complejidad espacial: O (1), la matriz devuelta no se incluye en la complejidad espacial.

Código Python de la solución del problema:

class Solution:
    def countBits(self, num: int) -> List[int]:
        res = []
        for i in range(num + 1):
            res.append(bin(i).count("1"))
        return res

Método 2: método de búsqueda de memoria

Idea de solución del problema:
en la solución violenta anterior, en realidad hay muchos cálculos repetidos. Por ejemplo, cuando i = 8, se requiere la situación en la que i = 4, 2, 1, 0 y estos valores se han calculado , ahora puede utilizar la búsqueda de memoria.

La llamada búsqueda de memoria consiste en guardar el resultado del cálculo cada vez que finaliza la función recursiva. En este caso, si se encuentra la misma entrada la próxima vez que recurra, consultará directamente y volverá de los resultados guardados sin repetir el cálculo nuevamente.

Por ejemplo, cuando i = 8, se requiere la situación de i = 4, y la situación de i = 4 se ha calculado antes, así que devuelva memo [4] directamente.

Complejidad: Complejidad de
tiempo: O (N), porque se recorre una vez, y cada solución se puede encontrar a partir de los resultados memorizados previamente.
Complejidad del espacio: O (N), utilizando el espacio auxiliar para guardar el resultado, el resultado del espacio es O (N).

Código Python de la solución del problema:

class Solution(object):
    def countBits(self, num):
        self.memo = [0] * (num + 1)
        res = []
        for i in range(num + 1):
            res.append(self.count(i))
        return res
    
    def count(self, num):
        if num == 0:
            return 0
        if self.memo[num] != 0:
            return self.memo[num]
        if num % 2 == 1:
            res = self.count(num - 1) + 1
        else:
            res = self.count(num // 2)
        self.memo[num] = res
        return res

Método tres: programación dinámica

De hecho, muchas veces, los métodos de programación dinámica se optimizan a partir de la búsqueda memorizada. Este problema también puede ser el mismo.

Método 2 En el proceso de memorizar la búsqueda, vemos que cada vez que se llama a la función recursiva, la función recursiva solo se ejecutará una vez, y será capturada por memo y devuelta. De hecho, puede eliminar la función recursiva y verificar el resultado directamente desde la matriz res.

Al mismo tiempo, la expresión de la ecuación de transferencia se optimiza como respuesta [i] = respuesta [i >> 1] + (i & 1).

Así que obtenga el siguiente esquema de programación dinámica.

Complejidad: Complejidad del
tiempo: O (N) O (N), porque se atraviesa una vez.
Complejidad del espacio: O (1) O (1), el espacio ocupado por el resultado devuelto no se incluye en la complejidad del espacio.

Código Python de la solución del problema:

class Solution:
    def countBits(self, num):
        res = [0] * (num + 1)
        for i in range(1, num + 1):
            res[i] = res[i >> 1] + (i & 1)
        return res

Autor: fuxuemingzhu
enlace: https://leetcode-cn.com/problems/counting-bits/solution/yi-bu-bu-fen-xi-tui-dao-chu-dong-tai-gui-3yog/
Fuente: force LeetCode (LeetCode) https://leetcode-cn.com/problems/counting-bits/

Método 4: operación bit a bit (muy recomendable)

Idea para la solución del problema:
puede cambiar la forma de pensar. Al calcular el "número de bits" de i, si hay un "número de bits" de 0≤j <i, se conoce el "número de bits" de j, e i solo tiene más representaciones binarias que j. Si obtiene un 1, puede obtener rápidamente el "número de un bit" de i.

Dejemos que los bits [i] denoten el "número de bits" de ii, entonces la relación anterior se puede expresar como: [j] + 1bits [i] = bits [j] +1.

Para un entero positivo x, si se puede conocer el entero positivo más grande y tal que y≤xey es una potencia entera de 2, entonces solo el bit más alto en la representación binaria de y es 1, y el resto son todos 0. En este momento, y se denomina x "Bit más significativo" de. Sea z = x − y, obviamente 0≤z <x, luego bits [x] = bits [z] +1.

Para juzgar si un entero positivo es una potencia entera de 2, puede usar la naturaleza de la operación AND bit a bit mencionada en el Método 1. Si el entero positivo y es una potencia entera de 2, solo el bit más alto en la representación binaria de y es 1, y el resto es 0, entonces y & (y − 1) = 0. Puede verse que el entero positivo y es una potencia entera de 2, si y solo si y & (y − 1) = 0.

Obviamente, el "número de bits" de 0 es 0. Utilice highBit para representar el bit más significativo actual, recorra cada entero positivo ii de 11 a num y realice las siguientes operaciones.

Si i & (i − 1) = 0, establezca highBit = i y actualice el bit más significativo actual.

i es 11 más que el "número de bits" de i-highBit. Dado que cada número se atraviesa de pequeño a grande, cuando se atraviesa hacia i, se conoce el "número de bits" de i-highBit. Sea bits [i] = bits [i − highBit] +1.

La matriz de bits resultante es la respuesta.

Código Python de la solución del problema:

class Solution:
    def countBits(self, num: int) -> List[int]:
        bits = [0]
        highBit = 0
        for i in range(1, num + 1):
            if i & (i - 1) == 0:
                highBit = i
            bits.append(bits[i - highBit] + 1)
        return bits

Autor: LeetCode-Solución
Enlaces: https://leetcode-cn.com/problems/counting-bits/solution/bi-te-wei-ji-shu-by-leetcode-solution-0t1i/
Fuente: botón de estancia (LeetCode) https://leetcode-cn.com/problems/counting-bits/

Supongo que te gusta

Origin blog.csdn.net/weixin_44414948/article/details/114323843
Recomendado
Clasificación