zoukankan      html  css  js  c++  java
  • [LeetCode] 338. Counting Bits(数比特位)

    Description

    Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.
    给定一个非负整数 num。对于从 0 到 num(端点包含)的每一个数 i,计算 i 的二进制表示里有多少个 1,然后以数组形式返回。

    Examples

    Example 1

    Input: 2
    Output: [0,1,1]
    

    Example 2

    Input: 5
    Output: [0,1,1,2,1,2]
    

    Follow up:

    • It is very easy to come up with a solution with run time O(n * sizeof(integer)). But can you do it in a linear time O(n) /possibly in a single pass?
      很容易就能想出时间复杂度为 O(n * sizeof(integer)) 的解法。但是你能在 O(n) 时间复杂度(或者说,一次遍历)解决它吗?

    • Space complexity should be O(n).
      空间复杂度应该是 O(n)。

    • Can you do it like a boss? Do it without using any bulitin function like __builtin_popcount in C++ or in any other language.
      你能像一个 boss 那样解答吗?不使用任何内置函数(例如 C++ 里的 __builtin_popcount 或者其它任何语言里的类似函数)解答。

    Hints

    1. You should make use of what you have produced already.
      你应该充分利用你已经生成的数据。

    2. Divide the numbers in ranges like [2-3], [4-7], [8-15] and so on. And try to generate new range from previous.
      将数列分成若干区间,例如 [2-3],[4-7],[8-15] 等等。依之前的规律生成新的区间。

    3. Or does the odd/even status of the number help you in calculating the number of 1s?
      或者说,这个数的奇偶性能否帮助你计算这个数的二进制表示中 1 的数量呢?

    Solution

    正如提示所说,O(n * sizeof(integer)) 时间复杂度的做法很容易就能想出来。但是这题的标签里竟然有动态规划,这是啥情况?提示里说让我们找规律,那就先把 0~15 内的数据都列出来,如下表格所示:

    i binary representation of i number of 1`s
    0 0000 0
    1 0001 1
    2 0010 1
    3 0011 2
    4 0100 1
    5 0101 2
    6 0110 2
    7 0111 3
    8 1000 1
    9 1001 2
    10 1010 2
    11 1011 3
    12 1100 2
    13 1101 3
    14 1110 3
    15 1111 4

    你说看不出有啥规律?那我从里面单独拿出一个奇数和一个偶数的例子:

    • 9 的二进制表示是 1001,有 2 个 1;4 的二进制表示为 0100,有 1 个 1。

    • 12 的二进制表示是 1100,有 2 个 1;6 的二进制表示为 0110,有 2 个 1。

    看出来了吗?一个数 num 的 1 的数量,是由其本身右移一位后的数的 1 的数量与自身奇偶性决定的,对于一个数的二进制 1 的数量 ( exttt{countBit}(x)) ,总有如下规律:

    [ exttt{countBit}(x) = egin{cases} exttt{countBit}( exttt{shiftRight}(x, 1)) & x 为偶数 \ exttt{countBit}( exttt{shiftRight}(x, 1)) + 1 & x 为奇数 end{cases} ]

    其中 ( exttt{shiftRight}(x, bits)) 表示将数 (x) 逻辑右移 (bits) 位。同时我们定义 ( exttt{countBit}(0) = 0) 以及 ( exttt{countBit}(1) = 1),这不就是天然的状态转移方程吗?于是使用动态规划法可以得到如下时间复杂度为 O(N) 的解法:

    class Solution {
        fun countBits(num: Int): IntArray {
            if (num == 0) {
                return intArrayOf(0)
            }
            if (num == 1) {
                return intArrayOf(0, 1)
            }
            val result = IntArray(num + 1)
            result[0] = 0
            result[1] = 1
    
            for (i in 2..num) {
                result[i] = if (i % 2 == 0) {
                    result[i shr 1]
                } else {
                    result[i shr 1] + 1
                }
            }
    
            return result
        }
    }
    
  • 相关阅读:
    在rhel6上安装Python 2.7和Python 3.3
    RHEL7 -- Linux搭建FTP虚拟用户
    RHCE7 -- IPv6
    RHEL7 -- nmcli的使用
    设置Adobe Reader打开PDF文件保持记忆功能
    iptalbes -F
    服务器IP地址后修改SQL Server配置
    配置SELINUX
    11G新特性 -- 分区表和增量统计信息
    11G新特性 -- Statistics Preferences
  • 原文地址:https://www.cnblogs.com/zhongju/p/13867632.html
Copyright © 2011-2022 走看看