技术图文:Python 位运算防坑指南
背景
我们先看这个题目:
- 标题:137. 只出现一次的数字 II
- 难度:中等
- https://leetcode-cn.com/problems/single-number-ii/
给定一个 非空 整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2]
输出: 3
示例 2:
输入: [0,1,0,1,0,1,99]
输出: 99
思路:
初始result = 0
,将每个数想象成 32 位的二进制,对于每一位的二进制的1累加起来必然是3N
或者3N + 1
(出现3次和1次);3N
代表目标值在这一位没贡献,3N + 1
代表目标值在这一位有贡献(=1),然后将所有有贡献的位记录到result
中。这样做的好处是如果题目改成k
个一样,只需要把代码改成count % k
即可,很通用并列去找每一位。
C# 语言
- 执行结果:通过
- 执行用时:112 ms, 在所有 C# 提交中击败了 91.53% 的用户
- 内存消耗:25.2 MB, 在所有 C# 提交中击败了 100.00% 的用户
public class Solution
{public int SingleNumber(int[] nums){int result = 0;for (int i = 0; i < 32; i++){int mask = 1 << i;int count = 0;for (int j = 0; j < nums.Length; j++){if ((nums[j] & mask) != 0){ count++;}}if (count % 3 != 0){result |= mask;}}return result;}
}
Python 语言
class Solution:def singleNumber(self, nums: List[int]) -> int:result = 0for i in range(32):mask = 1 << icount = 0for num in nums:if num & mask != 0:count += 1if count % 3 != 0:result |= maskreturn result
以上 Python 代码与 C# 代码逻辑完全一致,但提交时报错。错误信息如下:
输入:[-2,-2,1,1,-3,1,-3,-3,-4,-2]
输出:4294967292
预期结果:-4
我们发现:
-4 补码为 1111 1111 1111 1111 1111 1111 1111 1100
如果不考虑符号位
1111 1111 1111 1111 1111 1111 1111 1100 -> 4294967292
是不是很坑,C++,C#,Java等语言的整型是限制长度的,如:byte 8位,int 32位,long 64位,但 Python 的整型是不限制长度的(即不存在高位溢出),所以,当输出是负数的时候,会导致认为是正数!因为它把32位有符号整型认为成了无符号整型,真是坑。
我们对以上的代码进行修改,加入判断条件 if result > 2 ** 31-1:
超过32位整型的范围就表示负数了result -= 2 ** 32
,即可得到对应的负数。
- 执行结果:通过
- 执行用时:96 ms, 在所有 Python3 提交中击败了 19.00% 的用户
- 内存消耗:14.8 MB, 在所有 Python3 提交中击败了 25.00% 的用户
class Solution:def singleNumber(self, nums: List[int]) -> int:result = 0for i in range(32):mask = 1 << icount = 0for num in nums:if num & mask != 0:count += 1if count % 3 != 0:result |= maskif result > 2 ** 31-1:result -= 2 ** 32return result
技术分析
上面的问题解决了,我们在深入的探讨一下。
整数在内存中是以补码的形式存在的,输出自然也是按照补码输出。
class Program
{static void Main(string[] args){string s1 = Convert.ToString(-3, 2);Console.WriteLine(s1); // 11111111111111111111111111111101string s2 = Convert.ToString(-3, 16);Console.WriteLine(s2); // fffffffd}
}
但我们看一下 Python 的bin()
输出。
print(bin(3)) # 0b11
print(bin(-3)) # -0b11print(bin(-3 & 0xffffffff))
# 0b11111111111111111111111111111101print(bin(0xfffffffd))
# 0b11111111111111111111111111111101print(0xfffffffd) # 4294967293
是不是很颠覆认知,我们从结果可以看出:
- Python中
bin
一个负数(十进制表示),输出的是它的原码的二进制表示加上个负号,巨坑。 - Python中的整型是补码形式存储的。
- Python中整型是不限制长度的不会超范围溢出。
所以为了获得负数(十进制表示)的补码,需要手动将其和十六进制数0xffffffff
进行按位与操作,再交给bin()
进行输出,得到的才是负数的补码表示。
总结
这篇图文从一道Leetcode题目开始说起,发现C#语言与Python语言在利用二进制处理整型数据时存在不同,Python语言不属于强类型语言所以不限制整型的位数,表面上看好像方便使用其实就是个坑。大家使用时多加小心。好了今天就到这里吧,See You。
参考文献
- https://oi-wiki.org/math/bit/
- https://www.zhihu.com/question/314455297
往期活动
LSGO软件技术团队会定期开展提升编程技能的刻意练习活动,希望大家能够参与进来一起刻意练习,一起学习进步!
- Python基础刻意练习活动即将开启,你参加吗?
- Task01:变量、运算符与数据类型
- Task02:条件与循环
- Task03:列表与元组
- Task04:字符串与序列
- Task05:函数与Lambda表达式
- Task06:字典与集合
- Task07:文件与文件系统
- Task08:异常处理
- Task09:else 与 with 语句
- Task10:类与对象
- Task11:魔法方法
- Task12:模块
我是 终身学习者“老马”,一个长期践行“结伴式学习”理念的 中年大叔。
我崇尚分享,渴望成长,于2010年创立了“LSGO软件技术团队”,并加入了国内著名的开源组织“Datawhale”,也是“Dre@mtech”、“智能机器人研究中心”和“大数据与哲学社会科学实验室”的一员。
愿我们一起学习,一起进步,相互陪伴,共同成长。
后台回复「搜搜搜」,随机获取电子资源!
欢迎关注,请扫描二维码:
相关文章:

聊聊nginx报错499问题
序本文主要来聊一下nginx的access log当中出现的499问题。 问题描述499 CLIENT CLOSED REQUESTA non-standard status code introduced by nginx for the case when a client closes the connection while nginx is processing the request. 原因服务器返回http头之前ÿ…

UI设计需要报培训班学习吗
UI设计在很多企业已经是不可或缺的一个岗位了,所以UI设计的发展空间是非常大的,想要做UI设计师,光靠自学是不行的,那么UI设计需要报培训班学习吗?来看看下面小编的详细介绍就知道了。 UI设计需要报培训班学习吗?目前学习UI设计主…

技术图文:位运算技术在求解算法题中的应用
背景 前段时间,在知识星球立了一个Flag,这是总结Leetcode刷题的第一篇图文。 在总结这篇图文的时候,顺便把遇到的坑写了两篇辅助的图文,大家可以参考一下: 有符号整型的数据范围为什么负数比正数多一个?P…

JavaScript学习系列6 充实文档的内容
JavaScript 两项基本原则渐进增强:你应该总是从最核心的部分,也就是从内容开始。应该根据内容使用标记实现良好的结构;然后再逐步加强这些内容。平稳退化:不支持JavaScript也能访问基本内容。内容:我们在Html文件中编辑…

mapreduce中设置自定义的输入类,进行文本解析(默认以tab键为分隔符)
job.setInputFormatClass(KeyValueTextInputFormat.class);//此时map端输入的键的内容为第一个tab键以左的内容,值得内容为第一个tab键以右的内容转载于:https://www.cnblogs.com/le-ping/p/7788973.html

如何分辨Web前端培训机构的好坏
web前端在互联网行业有着非常高的薪水和很好的前景,想要学习web前端的人越来越多,对于web前端培训机构的选择让很多人犯了难,那么如何分辨Web前端培训机构的好坏呢?该如何选择呢?来看看下面的详细介绍。 如何分辨Web前端培训机构的好坏? 1…

mysql dba系统学习(19)配置mysql+lvs+keeplived实现Mysql读操作的负载均衡
配置mysqllvskeeplived实现Mysql读操作的负载均衡 环境: test1192.168.46.131master test2192.168.46.130slave备份test库 test3调度器 1、安装与配置Keepalived 首先在节点test1、test2上安装Keepalived软件,软件安装非常简单。 12345678910111213[root…
技术图文:浅析 C# Dictionary实现原理
背景 对于 C# 中的 Dictionary类 相信大家都不陌生,这是一个 Collection(集合) 类型,可以通过 Key/Value (键值对) 的形式来存放数据;该类最大的优点就是它查找元素的时间复杂度接近 O(1),实际项目中常被用来做一些数据的本地缓存…

思念水饺吃成泡沫水饺(图)思念质量门
思念再曝水饺吃出泡沫 !思念带着“创可贴汤圆”和“泡沫水饺”“拜晚年”了,而失去新国标的“护身符”,思念这次还要找出什么样的借口为汤圆里的创可贴和水饺里的泡沫找“台阶”下呢?思念汤圆刚被爆吃出创可贴,思念水饺…

jQuery动画的显示与隐藏效果
jQuery中用于控制元素显示和隐藏效果的方法如表1所示。 表1 控制元素的显示和隐藏 在表1中,参数speed表示动画的速度,可设置为动画时长的毫秒值(如1000),或预定的3种速度(slow、fast和normal);参数easing表示切换效果,默认效果为s…

技术图文:字典技术在求解算法题中的应用
背景 前段时间,在知识星球立了一个Flag,这是总结Leetcode刷题的第二篇图文。 在总结这篇图文的时候,顺便总结了 C# 中Dictionary类的实现,大家可以参考一下: 浅析 C# Dictionary实现原理 理论部分 C# 中字典的常…

[WCF REST] 解决资源并发修改的一个有效的手段:条件更新(Conditional Update)
条件获取(Conditional Update)可以避免相同数据的重复传输,进而提高性能。条件更新(Conditional Update)用于解决资源并发操作问题。如果我们预先获取一个资源进行修改或者删除,条件更新检验帮助我们确认资…
Netty 之 Zero-copy 的实现(下)
上一篇说到了 CompositeByteBuf ,这一篇接着上篇的讲下去。 FileRegion 让我们先看一个Netty官方的example // netty-netty-4.1.16.Final\example\src\main\java\io\netty\example\file\FileServerHandler.java public void channelRead0(ChannelHandlerContext ctx…

Java中final关键字如何使用?
final变量只能赋值一次,赋值的方式有三种: 1)声明变量时直接赋值; 2)非静态成员变量在{}块中赋值,静态成员变量在static{}块中赋值; 3)非静态成员变量在构造方法中赋值。 final修饰类 final类不能被继承,因此不会有子类。final类中…

技术图文:双指针在求解算法题中的应用
背景 前段时间,在知识星球立了一个Flag,这是总结Leetcode刷题的第三篇图文。 理论部分 Python list 的源码地址: https://github.com/python/cpython/blob/master/Include/listobject.h https://github.com/python/cpython/blob/master/O…

【CSON原创】HTML5游戏框架cnGameJS开发实录(外部输入模块篇)
返回目录 1.为什么我们需要外部输入模块? 在游戏中我们常常用到类似这样的操作:鼠标点击某位置,玩家对象移动到该位置,或者按鼠标方向键,玩家向不同方向移动,等等。这些操作无一不用与外部输入设备打交道。…

中国科协(深圳)海外人才离岸创新创业基地源创力中心开业,主打国际创业服务...
2017年9月28日,由深圳市科学技术协会主办、深圳市罗湖区人民政府支持,深圳市源创力离岸创新中心承办的“梧桐山基地开园仪式暨梧桐湾未来论坛”于深圳举办。 据介绍, “中国科协(深圳)海外人才离岸创新创业基地”是在深…

找java培训机构如何挑选
java技术在互联网行业的需求率还是非常高的,它的发展前景非常可观,想要学好java技术,那么寻找一个好的java培训机构是非常重要的,那么找java培训机构如何挑选呢?来看看下面的详细介绍。 找java培训机构如何挑选? 在选择…

技术图文:集合技术在求解算法题中的应用
背景 前段时间,在知识星球立了一个Flag,这是总结Leetcode刷题的第四篇图文。 理论部分 HashSet C# 语言中 HashSet<T> 是包含不重复项的无序列表,称为“集合(set)”。由于set是一个保留字,所以用HashSet来表示。 public…

sql server 2008数据导入Oracle方法
试了几种sql server数据导入Oracle的方法,发现还是sql server 的导入导出工具最好使。使用方法很简单,照着向导做就可以。不过使用中需要注意以下几点: 系统盘需要足够大。因为SSIS的临时文件都是生成在系统盘的,系统盘太小&#…

nginx+tomcat配置负载均衡集群
一、Hello world 1、前期环境准备 准备两个解压版tomcat,如何同时启动两个tomcat,方法如下: 首先去apache tomcat官网下载一个tomcat解压版。 解压该压缩包,生成n份tomcat 分别命名为 tomcat1,tomcat2, 然后…

参加UI设计培训要学多久
UI设计要学习的内容有很多,至于参加UI设计培训要学多久这个问题,要看你的学习能力和所在的UI设计培训机构都教些什么,我们来看看下面的详细介绍。 参加UI设计培训要学多久?千锋教育的课程大纲分享给大家参考学习一下: 阶段一&…

技术图文:C# 语言中的扩展方法
背景 前段时间,在知识星球立了一个Flag,在总结 Leetcode 刷题的第五篇图文时遇到了扩展方法 这个知识点,于是先总结一下。 1.扩展方法概述 扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以…

如何在ToolBar中显示文字和图标,自定义图标大小,并和MenuItem关联
要注意以下几个方面,先后顺序未必正确,有可能多设几次 1.设置ToolBar可以显示文字ToolBar.ShowCaption : True;2.设置ToolButton大小ImageList.WidthImageList.Height3.设置菜单关联4.设置运行时显示图标(这个是关键)ToolButton.Menuitum.ImageIndex要保证MenuItem所在的MainMe…

C#程序调用cmd执行命令
酷小孩 原文 C#程序调用cmd执行命令 对于C#通过程序来调用cmd命令的操作,网上有很多类似的文章,但很多都不行,竟是漫天的拷贝。我自己测试整理了一下。 代码: string str Console.ReadLine();System.Diagnostics.Process p new …

Java虚拟机的内存空间有几种
Java虚拟机的内存空间有几种?(1)问题分析: JVM(虚拟机)的内存划分 不同的数据使用的是哪一块内存空间 (2)核心答案讲解: Java虚拟机有那几块内存空间: 1)栈内存:方法运行时所进入的内存,里面还会存储程序的…

技术图文:排序技术在求解算法题中的应用
背景 前段时间,在知识星球立了一个Flag,这是总结Leetcode刷题的第五篇图文。 理论部分 C# 中的排序 对集合类的排序,我们通常使用位于 System.Core 程序集,System.Linq命名空间下,Enumerable静态类中的扩展方法。 …

如果有电脑——计算机达人成长之路(36)
5、电脑情缘(一)王新华的电脑 现在的大学生一般都有一个工具,就是计算机,尤其是计算机科学系的学生,几乎人手一台。对此,木鸿飞只能深深的说上一句:“幸福啊!” 现在人可能不能了解这…

Javascript中二进制数据处理方法
Javascript中二进制数据处理方法 转载于:https://www.cnblogs.com/motadou/archive/2012/02/19/2358514.html

正规Java培训机构是什么样的
正规Java培训机构是什么样的?这对于很多想真正学习到java技术的人来说是非常重要的,选择一个适合自己的靠谱的Java培训机构,学有所成工作也是比较稳定的,下面我们来看看详细的介绍。 正规Java培训机构是什么样的?其实对于这个问题…