Leetcode #338 比特位计数

目录

  • 题目描述
  • 解题思路
  • 我的代码
  • 心得

题目描述

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/counting-bits/

示例1:

输入: 2
输出: [0,1,1]

示例2:

输入: 5
输出: [0,1,1,2,1,2]

进阶:

  • 给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
  • 要求算法的空间复杂度为O(n)。
  • 你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。

解题思路

关键词:

  • 0~num中的每一个数字
  • 其二进制中 1 的个数

思路:

  • 法①:第一反应是通过内置函数bin()count(),一次遍历。
  • 法②:找到内部规律,通过动态规划求解。

内部规律:

数字 对应二进制 f() 返回对应二进制1的个数
0 0 f(0) = 0
1 1 f(1) = f(0) + 1
2 10 f(2) = f(1)
3 11 f(3) = f(2) + 1
4 100 f(4) = f(2)
5 101 f(5) = f(4) + 1
6 110 f(6) = f(3)
7 111 f(7) = f(6) + 1
8 1000 f(8) = f(4)

发现:

  • 根据规律的发现我们得出两个事实:
  • ①数字是奇数时:其值为前一数字(偶数)加 1。即,f(a) = f(a - 1) + 1。
  • ②数字是偶数时:其值与折半相同。即,f(a) = f(a/2)。
  • 例:f(3) = f(2) + 1 = f(1) + 1 = f(3/2) + 1 = f(3 >> 1) + 1
  • f(6) = f(6/2) = f(3) = f(6 >> 1)
  • f(7) = f(6) + 1 = f(3) + 1 = f(7/2) + 1 = f(7 >> 1) + 1

具体操作:

  • 数字折半可以使用位运算。a/2 = a >> 1。
  • 因为偶数的二进制尾数为0,奇数的为1, 所以是否“加1”,可以通过判断尾数是否“为1”来控制。

我的代码

法①:

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

时间复杂度: O(N∗sizeof(int))。
空间复杂度:O(1)。

法②:

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

时间复杂度: 仅遍历一次,是O(N)。
空间复杂度:O(1)。
Leetcode #338 比特位计数_第1张图片

心得

  • 位运算方面的规律还不是很了解,但对Dp问题有了更深入的认识。
  • 着手准备毕设了,争取3月末打好数据库与前端框架。

你可能感兴趣的:(Leetcode-笔记,#,动态规划,leetcode,算法,动态规划,python)