问题描述:给出一个非负整数num,对[0, num]范围内每个数都计算它的二进制表示中1的个数

Example:
For num = 5 you should return [0,1,1,2,1,2]

思路:该题属于找规律题,令i从0开始,设f(i)为i对应二进制表示中1的个数,写几对对应值就出来了。

很明显,规律就是[0, 1)部分各个值加1就构成了[1, 2)部分,[0, 2)部分各个值加1就构成了[2, 4)部分,[0, 4)部分各个值加1就构成了[4, 8)部分。

以此类推。

原因也很显然,是最高位的1,使二进制中1的个数多了1。

也就是从初始状态res = {0}, n = 1开始:

每次新增长度与res相等的序列newSeq,满足newSeq[i] = res[i] + 1,i = 0, 1, 2, …… , 2^(n-1)-1

然后把newSeq添加到res末尾。依次循环直到长度大于num+1。

其中res长度的增长过程是1——2——4——8——……——log2(num+1)——num。除了最后一步都是加倍增长。

解法

刚开始试着用链表list来动态增加(splice),把原来的list(l0)每个值都加1后构成新的list(l1),然后把l1插入到l0末尾。

这样l0大小从1到2到4到8……一直到log2(len),再把剩下的len - log2(len)个元素构成新的list(l1)插入到末尾。

class Solution {
public:
vector<int> countBits(int num) {
int len = num + 1;
list<int> l0 = { 0 };
int n = 1;
bool b = true;
while (n < len) {
if (len - n < n) {
int newCnts = len - n;
auto it = l0.cbegin();
for (int i = 0; i < newCnts; ++i) {
l0.push_back(1 + *it++);
}
break;
} else {
list<int> l1;
auto it = l0.cbegin();
while (it != l0.cend())
l1.push_back(1 + *it++);
l0.splice(l0.end(), l1);
n *= 2;
}
}
vector<int> res(len);
auto it1 = l0.cbegin();
auto it2 = res.begin();
while (it2 != res.end())
*it2++ = *it1++;
return res;
}
}; // 15/15 96ms 20.09%

然后发现代码又长,效率不怎样,这里splice比起在vector中计算元素的位置没有什么优势,问题在于每次push_back都要新申请一个元素的空间,最后还要重新转换成vector(PS:leetcode给出的C++函数签名的返回值是vector),这种靠链接list的小伎俩还不如老老实实用vector。(好吧我承认是被STL的list排序算法影响到了……)

于是用vector写了下,代码变短了而且效率还可以(目测可以精简下代码)

class Solution {
public:
vector<int> countBits(int num) {
const int len = num + 1;
vector<int> res(len); int nb = 1;
int ne = nb << 1;
res[0] = 0;
while (ne < len) {
for (int i = nb; i < ne; ++i)
res[i] = res[i - nb] + 1;
nb = nb << 1;
ne = nb << 1;
}
for (int i = nb; i < len; ++i)
res[i] = res[i - nb] + 1; return res;
}
}; // 15/15 88ms 53.16%

试着改进了下,就是对于每个新的序列,比如[4, 8)对应{1, 2, 2, 3},[1, 4)对应{0, 1, 1, 2}

[4, 6)区域和[2, 4)区域的值是一样的,而[6, 8)区域的值是[2, 4)区域对应值加1。这样每次遍历[nb + (ne-nb)/2, ne)再运算两次即可,用temp保留遍历的值,temp和temp+1赋给新的位置。这样省去了一次+1操作。

但是问题是这样增加了一次赋值操作,测试运行时间是一样的,暂时就此打住吧,有空再看看优秀解法。

【Leetcode 338】 Counting Bits的更多相关文章

  1. 【LeetCode 229】Majority Element II

    Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorit ...

  2. 【LeetCode练习题】Permutation Sequence

    Permutation Sequence The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and ...

  3. 【LeetCode题解】二叉树的遍历

    我准备开始一个新系列[LeetCode题解],用来记录刷LeetCode题,顺便复习一下数据结构与算法. 1. 二叉树 二叉树(binary tree)是一种极为普遍的数据结构,树的每一个节点最多只有 ...

  4. 【LeetCode题解】136_只出现一次的数字

    目录 [LeetCode题解]136_只出现一次的数字 描述 方法一:列表操作 思路 Java 实现 Python 实现 方法二:哈希表 思路 Java 实现 Python 实现 方法三:数学运算 思 ...

  5. 【LeetCode题解】7_反转整数

    目录 [LeetCode题解]7_反转整数 描述 方法一 思路 Java 实现 类似的 Java 实现 Python 实现 方法二:转化为求字符串的倒序 Java 实现 Python 实现 [Leet ...

  6. 【LeetCode题解】350_两个数组的交集Ⅱ

    目录 [LeetCode题解]350_两个数组的交集Ⅱ 描述 方法一:映射 Java 实现 Python 实现 类似的 Python 实现 方法二:双指针 Java 实现 Python 实现 [Lee ...

  7. 【LeetCode题解】349_两个数组的交集

    目录 [LeetCode题解]349_两个数组的交集 描述 方法一:两个哈希表 Java 实现 类似的 Java 实现 Python 实现 类似的 Python 实现 方法二:双指针 Java 实现 ...

  8. 【LeetCode题解】94_二叉树的中序遍历

    目录 [LeetCode题解]94_二叉树的中序遍历 描述 方法一:递归 Java 代码 Python代码 方法二:非递归 Java 代码 Python 代码 [LeetCode题解]94_二叉树的中 ...

  9. 【LeetCode题解】144_二叉树的前序遍历

    目录 [LeetCode题解]144_二叉树的前序遍历 描述 方法一:递归 Java 代码 Python 代码 方法二:非递归(使用栈) Java 代码 Python 代码 [LeetCode题解]1 ...

随机推荐

  1. Loadrunner 11检查点使用方法总结

    在使用Loadrunner 11进行性能测试中,有时需要对性能测试中的功能是否全部正确进行判断.这里就需要用到“检查点”,本文总结了常用三种协议下检查点的使用方法,希望阅读本文后的小伙伴们能够掌握其使 ...

  2. Prism 4 文档 ---第5章 实现MVVM模式

        MVVM模式有助于清楚的区分应用程序界面的业务层和展现层.保持一个清晰的应用程序逻辑和UI分离有助于处理开发和设计过程中大量的问题,同时,使得应用程序的测试,维护,和扩展更加容易.MVVM也可 ...

  3. vue单独给页面设置body属性

    因项目需求:用户个人详细信息页面设置背景色,之前在这个页面设置最外层div发现不行.因为app.vue影响了它.后来直接在页面上用body设置样式,发现影响了其他页面. 后来想了通过vue的生命周期来 ...

  4. 数据库连接错误:CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.

    学习Spring整合Hibernate的知识,新建一个工程,代码结构如下: 按如下步骤整合: 代码如下: hibernate.cfg.xml: <?xml version="1.0&q ...

  5. 查询表名及列名长度超过一定长度的SQL

    apple=# select * from (select a.relname, char_length(a.relname) as tb_name_length, b.attname, char_l ...

  6. PostgreSQL copy命令使用记录

    上篇写到用pg_bulkload来导入数据,但是实际的环境是solaris,pg_bulkload还不支持,于是用copy的方式,下面附上脚本 -bash-4.1$ cat copy.sh #!/bi ...

  7. ETL学习整理 PostgreSQL

    ETL分别是“Extract”.“ Transform” .“Load”三个单词的首字母缩写也就是“抽取”.“转换”.“装载”,但我们日常往往简称其为数据抽取. ETL是BI/DW(商务智能/数据仓库 ...

  8. Python报错IOError: [Errno 22] invalid mode ('r') or filename

    IOError: [Errno 22] invalid mode ('r') or filename: 这种错误的出现是在使用built-in函数file()或者open()的时候. 或者是因为文件的 ...

  9. Recording︱有价值的各类AI、机器学习比赛心得、经验抄录

    今年kaggle华人优胜团队很多,所以经验.心得不少,都是干货慢慢收集. 一.[干货]Kaggle 数据挖掘比赛经验分享 github:https://github.com/ChenglongChen ...

  10. apk系统签名命令

    java -jar signapk.jar platform.x509.pem platform.pk8 D:/ClockSetting.apk D:/ClockSettingSigned.apk 需 ...