[leetcode] Counting Bites

本文介绍了一种使用动态规划方法快速计算从0到给定数字范围内所有整数二进制表示中1的数量。通过分析不同数字间的二进制结构,找到了有效的状态转移方程,实现了线性时间复杂度的算法。

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.

Example:
For num = 5 you should return [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 linear time O(n) /possibly in a single pass?
  • Space complexity should be O(n).
  • Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.

分析:题目意思很明确,翻译一下:一个数字num,要求找0——num中每个数字的二进制中有多少个1。题目也明确了最容易想到的方法的时间复杂度是O(n*sizeof(integer)),就是一个循环过去,在每个循环里调用一个函数来计算这个数字有多少个1。这个方法就不展示了,代码也很容易写。这里我准备说一下第二个思路,用动态规划。
思路二:动态规划。首先来看一下1——15各个数字的情况:
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

       可以确定的是当前状态dp[i]是与前面的状态有关的。我们知道一个正整数n,如何去找状态转移方程呢。考虑位运算,将n的二进制右移一位,那么高位补零,得到一个数字m,那么n二进制中1的个数就比m二进制中1的个数多一个n的最低为是否为1了。状态转移方程如下:dp[i]=dp[i>>1]+i&1;代码如下:

1 class Solution {
2    public int[] countBits(int num) {
3         int[] dp = new int[num+1];
4         for ( int i = 1 ; i < num+1 ; i ++ ) dp[i]=dp[i>>1]+(i&1);
5         return dp;
6     }
7 }

      还有一种动态规划的方法如下:n&(n-1)是用来判断这个数是否是2的指数,若结果为0,就是2的指数。其实n&(n-1)的作用是将n的二进制中最低为改为0。在我们的题目中,状态转移方程为:dp[i]=dp[i&(i-1)]+1。代码就不放上去了,但是我还是没有看懂状态转移方程的联系。不过分析了一i下,发现确实是对的。。

转载于:https://www.cnblogs.com/boris1221/p/9313668.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值