简单动态规划的实现(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;    }

运行成功了但是花费的复杂度惨不忍睹。

简单动态规划的实现(Leetcode 338. 比特位计数)


优化


优化的时候看了看其他人的代码,感觉以后做算法题还是不能调用函数来做,尽可能用基本的代码实现,最好还是用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. 比特位计数)的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode 338. Counting Bits

[动态规划]338. 比特位计数

(动态规划递归) leetcode 87. Scramble String

Leetcode动态规划简单题

leetcode 53. 最大子序和

动态规划LeetCode[简单]题全解