LeetCode-Python/Java-338. 比特位计数

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

示例 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,每个数都按照常规方法(不断除以2)求其二进制中有多少个1。

class Solution(object):
    def countBits(self, num):
        """
        :type num: int
        :rtype: List[int]
        """
        res = list()
        for i in range(num + 1):
            res.append(self.getOne(i))
        
        return res
    
    def getOne(self, n):
        binary = list()
        while(n >= 2):
            binary.append(n % 2)
            n = n // 2
        binary.append(n)
        # print binary
        return sum(binary)

第二种思路:

想起来《剑指Offer》里提到的结论:如果一个数 i 和 i - 1 做与运算,那么 i 的二进制表示形式中的最右边一个 1 会变成0 。根据这个结论可以优化统计每个数中 1 的个数的函数getOne。

class Solution(object):
    def countBits(self, num):
        """
        :type num: int
        :rtype: List[int]
        """
        res = list()
        for i in range(num + 1):
            res.append(self.getOne(i))
        
        return res
    
    def getOne(self, n):
        cnt = 0
        while(n):
            cnt += 1
            n = n & (n - 1)
        return cnt

第三种思路:

在第二种思路的基础上,利用动态规划的思想。

如果我们已经知道了 i & i -1 这个数字的1的个数cnt,那么根据上面的提到的结论, i 这个数字中 1 的个数就是 cnt + 1。

所以不难得到状态转移方程: dp[i] = dp[i &  (i - 1)] + 1

class Solution(object):
    def countBits(self, num):
        """
        :type num: int
        :rtype: List[int]
        """
        dp = [0 for i in range(num + 1)]
        for i in range(1, num + 1):
            dp[i] = dp[i & (i - 1)] + 1
        
        return dp
class Solution {
    public int[] countBits(int num) {        
        int[] res = new int[num + 1];
        for (int i = 1; i <= num; i++){
            res[i] = res[i &(i - 1)] + 1;
        }
        return res;
    }
}

 

你可能感兴趣的:(Leetcode,Python,Java)