简单动态规划的实现(Leetcode 338. 比特位计数)
Posted 二十一克日记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单动态规划的实现(Leetcode 338. 比特位计数)相关的知识,希望对你有一定的参考价值。
背景
想到五月就是蓝桥杯决赛了,而自己还是什么都不会的渣渣,感觉还是得花点时间找找代码感觉。听人说蓝桥杯基本上动态规划加贪心算法基本就够省二的水平了,因此还是想从动规入手。
题目描述
题目来源于Leetcode 338.比特位计数。
官方描述
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 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)来执行此操作。
题目分析
第一眼看到这个题以为是要我从计算二进制的角度去找计算的规律,但是稍微列了两三个数就发现没有必要,规律十分明显。
简单计算出了16个数就能够直观的看出来,前23个数中,后2 2个数的1的个数恰好都是前22个数的1的个数加1得到的。当然对于8、4、2个数也成立。
其实从数学的角度也完全可以分析出规律,任何一个数n,都能写成2i+k的形式,这里的k是n对2i取余的值,而2i的二进制一定是1000…的形式,即1的个数是1。因此n的二进制的1的个数都等于k的二进制的1的个数加上1。
程序
public int[] countBits(int num) {
int []result = new int[num+1];
int i,j=0;
result[0] = 0;
for(i=1;i<num+1;i++)
{
if(Math.pow(2,j+1)<=i)
{
j++;
}
result[i] = result[i-(int)Math.pow(2,j)]+1;
}
return result;
}
运行成功了但是花费的复杂度惨不忍睹。
优化
优化的时候看了看其他人的代码,感觉以后做算法题还是不能调用函数来做,尽可能用基本的代码实现,最好还是用c。蓝桥结束之后换成c再刷Leetcode。再有就是感到大佬太强了,打死我我也想不出这种方法。
优化的角度主要在二进制计算上,对于n位的二进制串,取其高n-1位,则此n位二进制串中1的个数或者等于n-1位二进制串中1的个数,或者等于n-1位二进制串中1的个数(取决于最后一位是否为1)。
public int[] countBits(int num) {
int []result = new int[num+1];
int i;
result[0] = 0;
for(i=1;i<num+1;i++)
{
result[i] = result[i>>1]+(1&i); //(1&i)表示最后一位的值(1或0)
}
return result;
}
这次时间花费只消耗了3ms,但是内存消耗还是很可怕。不是很清楚应该怎么解决内存消耗。
这几天疲惫的打不开电脑,迟了迟了(sorry抓猫!!!)点击蓝字阅读抓猫原文。
以上是关于简单动态规划的实现(Leetcode 338. 比特位计数)的主要内容,如果未能解决你的问题,请参考以下文章