复盘二进制的习题(2)
338 Counting Bits。输入一个整数n,对于 0 ≤ i ≤ num,计算每个数的二进制1的个数。例如:num = 5 返回 [0,1,1,2,1,2]。希望能在O(n)的时间内完成。这里有动态规划的思想。
思路一:
十进制数 | 二进制 | 表示 |
---|---|---|
0 | 000 | 0 |
1 | 001 | 1+(0的bits) |
2 | 010 | 1 |
3 | 011 | 1+(1的bits) |
4 | 100 | 1 |
5 | 101 | 1+(1的bits) |
6 | 110 | 1+(2的bits) |
7 | 111 | 1+(3的bits) |
8 | 1000 | 1 |
9 | 10001 | 1+(1的bits) |
10 | 10010 | 1+(2的bits) |
11 | 10011 | 1+(3的bits) |
… |
观察可以发现,值为2n2^n的时候,1的位数为1。其他情况下数,就是1+【从0开始的数1的位数】。
public int[] countBits3(int num) {int[] r = new int[num+1];int p = 1,i=0;while(p<=num){if((p&(p-1))==0) i=0;r[p++] = 1+r[i++];}return r;
}
思路二:发现一个规律:,7=111 ,由011->111添加了1个1;6=110,由011->110,1的个数不变,但是1的位置变了。从0daonum是一个不断变换1的位置或者不断加1的过程,这样就将任意一个数i,与i/2联系起来了。
public int[] countBits(int num) {int[] r = new int[num+1];for(int i =1;i<=num;i++){r[i] = r[i/2]+(i&1);}return r;
}
i&1,当数字为偶数就加0,如果是奇数就加1。
318 Maximum Product of Word Lengths。最大的单词长度乘积。输入一个字符串数组words,返回最大的length(words[i])*length(words[j]),i≠ji \ne j,并且单词i和单词j不含有公共字符。
思路一:难点是判断两个字符串是否包含相同字母。可以一个个遍历找到,效率会比较低。看看用位运算能怎么做。一共26个小写字母。表示不同的字母可以用one-hot类型表示(从词向量表示方法得到的启示)。
z = 10000…000(一共25个0)
y = 01000…000(一共25个0)
…
a = 0000…001
用26位的二进制表示不同的字母。
这样一个字符串 abc = 000….111
azc = 100…..101
两个字符串的值做与操作。如果结果为0,则说明没有相同字符。
public int maxProduct(String[] words) {int n = words.length;int[] values = new int[n];for (int i = 0; i < n; i++) {for (int j = 0; j < words[i].length(); j++) {values[i] |= (1 << (words[i].charAt(j) - 'a'));}}int maxproduct = 0;for (int i = 0; i < n - 1; i++) {for (int j = i + 1; j < n; j++) {if ((values[i] & values[j]) == 0) {if (words[i].length() * words[j].length() > maxproduct) {maxproduct = words[i].length() * words[j].length();}}}}return maxproduct;}
137 Single Number II。给定一个数组,每个数字出现三次,只有一个数字出现了一次。找到这个数字。
思路一:以前有个题目是说每个字母出现两次,只有一个字母出现了一次。这样用异或操作,就能找到只出现了一次的字母。但是出现三次?这里方法不管用了。
计算数组中所有数字的每一bit1的个数。1=01,如果数组中有三个1,那么第0位的1就有3个,3%3=0。你肯定会问题如果数组中有三个1和3呢?那第0位的1就会有6个,6%3=0。但是如果只有2个3,那第0位的1就只有5个,5%3!=0。那3就是要找的数字了。
public int singleNumber(int[] nums) {int result = 0;for (int j = 0; j < 32; j++) {int sum = 0;for (int i = 0; i < nums.length; i++) {sum += ((nums[i] >> j) & 1);}result += ((sum % 3)<<j);}return result;
}
260 Single Number III。输入数组nums,每个数字都恰好出现了两次。但是有两个数字,都只出现了一次。找到这两个数字。
思路:记录只出现了1次的两个数分别为a,b。
出现了2次的时候,找不同,肯定需要异或操作。对所有nums的元素做异或,最后得到的是r=a|b。如果r的第i位等于1,那说明a和b在这个位置是有分歧的。我们利用这一个bit就可以将nums数组分为第i位是0和第i位是1,两个部分。这个时候再做异或,就能去掉出现了两次的数,留下只有一次的数。
只留下一个数某一位为1,其他都为0,的操作是:n &=-n。
public int[] singleNumber(int[] nums) {int[] ans = new int[2];int diff = 0;for (int num : nums) {diff ^= num;}diff &= -diff;for (int num : nums) {if ((num & diff) == 0) {ans[0] ^= num;} else {ans[1] ^= num;}}return ans;
}
78 subsets
思路:求子集,就是将数组中每一个元素,或者取或者不取,组合起来。从二进制的角度来表示。例如nums=[1,2,3]。下标分别是 0,1,2。每次取一个,2个,三个就遍历完成了。
用1表示取这一位的数字。
下标: 0 1 2
组合 0 0 0 =0
1 0 0 =4
0 1 0 =2
0 0 1 =1
1 1 0 =6
1 0 1 =5
0 1 1 =3
1 1 1 =7
发现下标用0 1 表示后的值就是从0到7. 7=2^3-1。所以找到规律。
做了这么久,第一次直接找到最佳回答。
显然还可以用深度优先搜索的思路理解。
public List<List<Integer>> subsets(int[] nums) {List<List<Integer>> result = new ArrayList<List<Integer>>();int n = nums.length;int total = (1<<n)-1;for(int i=0;i<=total;i++){List<Integer> list = new ArrayList<Integer>();for(int j=0;j<n;j++){if(((i>>j) &1)==1){list.add(nums[j]);}}result.add(list);}return result;}
总结:这次关于二进制习题的复盘就结束了。整个做题的过程还是比较沮丧的。平时二进制操作用的比较少。前面的习题基本都是得看答案才能知道二进制该怎么用。这些操作在笔记中,用加粗符号标记出来了。当习题做到中间的时候,已经开始能想到用什么操作,能实现什么功能了。但是还不能完全做对。到了最后终于能找到感觉了。这也说明了练习,总结,才能掌握一门技巧。多次练习、总结终会学到一门技巧。解决问题过程中,对规律的观察和总结,是解题的关键。
复盘二进制的习题(2)相关推荐
- 复盘二进制的习题(1)
本文是对近期二进制专题的leetcde习题的复盘.文中的解决思路来源于leetcode的讨论,以及一些网页. 342 判断一个整数(32bits)是否是4的次幂. 写出4i,i=0,1,2,3,4.. ...
- 深入理解二进制的一些用法及题目详解(一定可以帮你学会二进制的习题哟)
在这篇博客中我会首先为大家介绍关于表达式求值中的隐式类型转换,然后为大家详细介绍一些与二进制有关的习题,帮助大家也更好的理解二进制~ 文章目录 一.隐式类型转换
- 《算法竞赛入门经典(第2版)》——学习记录
前言: 这里主要记录本人在学习紫书过程中充分理解过的题目的AC代码,便于以后回顾时查找代码和思路,毕竟看别人的真的有点难懂.此外,本书甚至是本书之外的相关知识学习也可能在此留下记录. 作为一只 ...
- 算术编码二进制例题a1a2a3a4_Chap5_思考题与习题.pdf
Chap5 思考题与习题 参考答案 5 1 将下表所列的信源进行六种不同的二进制编码 试问 消息 概率 C1C2C3C4C5C6 a1 a2 a3 a4 a5 a6 1 2 1 4 1 16 1 16 ...
- 十进制、十六进制、二进制习题
1.查看机器级程序的时候,理解十六进制和二进制格式之间的关系很重要,做点练习能够让你的转换更加熟练. 2.这个问题给你一个机会思考2的幂和它们的十六进制表示. 3.这个问题给你一个机会试着对一些小的数 ...
- 【习题】习题 1 - 用代码将二进制转换为十进制
欢迎来到博主 Apeiron 的博客,祝您旅程愉快 ! 时止则止,时行则行.动静不失其时,其道光明. 目录 1.缘起 2.算法描述 3.示例代码 4.相关知识点 5.总结 1.缘起 我以前在计算二进制 ...
- 习题10-7 十进制转换二进制 (15分)
本题要求实现一个函数,将正整数n转换为二进制后输出. 函数接口定义: void dectobin( int n ); 函数dectobin应在一行中打印出二进制的n.建议用递归实现. 裁判测试程序样例 ...
- 习题10-7 十进制转换二进制 (15 分)
本题要求实现一个函数,将正整数n转换为二进制后输出. 函数接口定义: void dectobin( int n ); 函数dectobin应在一行中打印出二进制的n.建议用递归实现. 裁判测试程序样例 ...
- 习题10-7 十进制转换二进制
本题要求实现一个函数,将非负整数n转换为二进制后输出. 函数接口定义: void dectobin( int n ); 函数dectobin应在一行中打印出二进制的n.建议用递归实现. 裁判测试程序样 ...
最新文章
- IAR FOR ARM 各版本号,须要的大家能够收藏了
- 删除顺序表指定下标的元素
- 【转】PBR基于物理的渲染
- linux java so 历险
- java web移植 遇到Project facet Java version 1.7 is not supported
- 【sinatra】安装测试
- 力扣-389 找不同
- 60套漂亮的的免费 PSD 界面设计元素包资源(系列二)
- p6spy oracle,p6spy简单使用
- deepstream imagedata multistream 中文注释数据流
- 【魔兽世界插件】魔兽世界插件实战笔记从入门到放弃的心理历程,宏、插件和辅助的实战编写笔记和视频记录
- moment 计算日期差
- UI设计书籍推荐,这三本好书你不能错过
- Can't locate Time/HiRes.pm in @INC错误的处理方法 perl安装不全
- 学画画要花多少钱_孩子学画画大约需要多少钱呢?
- Python百练成钢002-计算自幂数
- 关于轩辕剑3外传 swd3eDvd.exe报错问题
- 男生总会误解女生的14个地方。【爱她就停下两分钟看看吧!】
- linux新建挂载目录命令,告诉你Ubuntu添加新分区并设置挂载点的方法及命令
- Vue 路由懒加载和动态加载
热门文章
- Hibernate--使用xml配置映射关系
- EJB是什么?EJB的概念分析与理解(copy)
- linux 进程线程拓展
- [BZOJ 1085] [SCOI2005] 骑士精神 [ IDA* 搜索 ]
- Windows Mobile开发应该选择哪种开发语言?
- 如何在textarea中显示html代码
- 鸿蒙系统开发资金,华为终于动手,将拿出超十亿资金,开发者们有福了
- java 调用linux 脚本并获取返回值
- MySQL 常用需求写法 记录一下
- nuxt引用static或者assets目录下资源注意事项