1.1 变量、运算符与数据类型
1.1.1 注释
1.在Python中,#
表示注释,作用于整行(不同行将失效)。
2.''' '''
或""" """
表示区间注释,在三引号之间的不同行内容都可以被注释。
1.1.2 运算符
Python中的运算符可以分为6类:算术运算符、比较运算符、逻辑运算符、位运算符、三元运算符、其他运算符。
1.1.2.1 算术运算符
操作符 | 名称 | 示例 |
---|---|---|
+ | 加 | 1+1 == 2 |
- | 减 | 2-1 == 1 |
* | 乘 | 3*4 == 12 |
/ | 除 | 3/4 == 0.75 |
// | 整除(向下取整) | 3//4 == 0 |
% | 取余 | 3%4 == 3 |
** | 取幂 | 2**3 == 8 |
1.1.2.2 比较运算符
操作符 | 名称 | 示例 |
---|---|---|
> | 大于 | 2>1 |
>= | 大于等于 | 2>=(2 or 1) |
< | 小于 | 1<2 |
<= | 小于等于 | 2<=(2 or 5) |
== | 等于 | 3==3 |
!= | 不等于 | 3!=5 |
1.1.2.3 逻辑运算符
操作符 | 名称 | 示例 |
---|---|---|
and | 与 | (2>1) and (3>7) == False |
or | 或 | (1>3) or (2<9) == True |
not | 非 | not(2>1) == False |
1.1.2.4 位运算符
操作符 | 名称 | 示例 |
---|---|---|
~ | 按位取反 | ~0100 == 1011 |
& | 按位与 | 0100 & 1111 == 0100 |
| | 按位或 | 0100 | 1111 == 1111 |
^ | 按位异或 | 0100 ^ 1111 == 1011 |
<< | 左移 | 4<<2 表示整数4按位左移2位 |
>> | 右移 | 4>>2 表示整数4按位右移2位 |
位运算符的具体内容见1.2节。
1.1.2.5 三元运算符
有了三元操作符的条件表达式,你可以使用一条语句来完成以下的条件判断和赋值操作。
x, y = 4, 5
if x < y:
small = x
else:
small = y
#结果
4
1.1.2.6 其他运算符
操作符 | 名称 | 示例 |
---|---|---|
in | 存在 | 'A' in ['A', 'B', 'C'] == True |
not in | 不存在 | 'h' not in ['A', 'B', 'C'] == True |
is | 是 | "hello" is "hello" == True |
is not | 不是 | "hello" is not "hello" == False |
注意!!!
is
,is not
对比的是两个变量的内存地址==
,!=
对比的是两个变量的值- 比较的两个变量,指向的都是地址不可变的类型(str等),那么
is
,is not
和==
,!=
是完全等价的。 - 对比的两个变量,指向的是地址可变的类型(list,dict,tuple等),则两者是有区别的:内存地址不同。
1.1.2.7 运算符的优先级
- 一元运算符优于二元运算符。(一元运算的操作对象只有1个,二元运算的操作对象只有2个)
- 算术运算 > 移位运算 > 位运算 > 逻辑运算。
1.1.3 变量和赋值
- 变量名可以包括字母、数字、下划线,但变量名不能以数字开头。
- Python 变量名是大小写敏感的,
foo
不等于Foo
。 - 字符或字符串可以直接相加,组成更长的字符串。
1.1.4 数据类型与转换
类型 | 名称 | 示例 |
---|---|---|
int | 整型<class 'int'> | -876, 10 |
float | 浮点型<class 'float'> | 3.1415, -11.1 |
bool | 布尔型<class 'bool'> | True, False |
Python里面万物皆对象object
,也包括整型。所有对象都拥有相应的属性attributes
和方法method
。
dit()
函数可以查看某一对象的方法的目录。help()
函数可以查看某一对象的属性和方法的详细介绍。
- 浮点数tip:
decimal
函数库里的Decimal
对象和getcontext()
方法来控制需要保留的小数点位。prec
默认为28。例如:
decimal.getcontext().prec = 4
c = Decimal(1) / Decimal(3)
print(c)
# 0.3333
- 布尔型tip:确定
bool(X)
的值,要看X
是不是空,空的话就是False
,不空的话就是True
。
type()
函数可以查看一个变量的数据类型。
isinstance(object, classinfo)
判断对象object
是否是一个已知的类型classinfo
(例如int
,float
,str
等)。
type()
不会认为子类是一种父类类型,不考虑继承关系。isinstance()
会认为子类是一种父类类型,考虑继承关系。- 如果判断两个类型是否相同,推荐使用
isinstance()
。
类型转换
- 转换为整型
int(x, base = 10)
- 转换为字符串
str(object = ' ')
- 转换为浮点型
float(x)
1.1.5 print()
函数
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
- 将对象以字符串表示的方式格式化输出到流文件对象
file
里。其中所有非关键字参数都按str()
方式进行转换为字符串输出; - 关键字参数
sep
是实现分隔符,比如多个参数输出时想要输出中间的分隔字符; - 关键字参数
end
是输出结束时的字符,默认是换行符\n
; - 关键字参数
file
是定义流输出的文件,可以是标准的系统输出sys.stdout
,也可以重定义为别的文件; - 关键字参数
flush
是立即把内容输出到流文件,不作缓存。
1.2 位运算
1.2.1 原码、反码和补码
二进制有三种不同的表示形式:原码、反码和补码,计算机内部使用补码来表示。
原码:就是其二进制表示(注意,最高位是符号位)。
00 00 00 11 -> 3
10 00 00 11 -> -3
反码:正数的反码就是原码,负数的反码是符号位不变,其余位取反(对应正数按位取反)。
00 00 00 11 -> 3
11 11 11 00 -> -3
补码:正数的补码就是原码,负数的补码是反码+1。
00 00 00 11 -> 3
11 11 11 01 -> -3
1.2.2 按位非操作~
~
把num的补码中的 0 和 1 全部取反(0 变为 1,1 变为 0)有符号整数的符号位在~
运算中同样会取反。
00 00 01 01 -> 5
~
11 11 10 10 -> -6
#################
11 11 10 11 -> -5
~
00 00 01 00 -> 4
1.2.3 按位与操作&
只有两个对应位都为 1 时才为 1。
00 00 01 01 -> 5
&
00 00 01 10 -> 6
----------------
00 00 01 00 -> 4
1.2.4 按位或操作|
只要两个对应位中有一个 1 时就为 1。
00 00 01 01 -> 5
|
00 00 01 10 -> 6
----------------
00 00 01 11 -> 7
1.2.5 按位异或操作^
只有两个对应位不同时才为 1。
00 00 01 01 -> 5
^
00 00 01 10 -> 6
----------------
00 00 00 11 -> 3
1.2.6 按位左移操作 <<
num << i
将num
的二进制表示向左移动i
位所得的值。
00 00 10 11 -> 11
11 << 3
-----------------
01 01 10 00 -> 88
1.2.7 按位右移操作 >>
num >> i
将num
的二进制表示向右移动i
位所得的值。
00 00 10 11 -> 11
11 >> 2
-----------------
00 00 00 10 -> 2
1.2.8 利用位运算实现快速计算
- 通过
<<
和>>
快速计算2的倍数问题。
n << 1 -> 计算 n*2
n >> 1 -> 计算 n/2,负奇数的运算不可用
n << m -> 计算 n*(2^m),即乘以 2 的 m 次方
n >> m -> 计算 n/(2^m),即除以 2 的 m 次方
1 << n -> 2^n
- 通过
^
快速交换两个整数。
a ^= b
b ^= a
a ^= b
- 通过
a & (-a)
快速获取a
的最后为 1 位置的整数。
00 00 01 01 -> 5
&
11 11 10 11 -> -5
-----------------
00 00 00 01 -> 1
##################
00 00 11 10 -> 14
&
11 11 00 10 -> -14
------------------
00 00 00 10 -> 2
1.2.9 利用位运算实现整数集合
一个数的二进制表示可以看作是一个集合(0 表示不在集合中,1 表示在集合中)。
比如集合{1, 3, 4, 8}
,可以表示成01 00 01 10 10
而对应的位运算也就可以看作是对集合进行的操作。下表更详细表示:
9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |
8 | 4 | 3 | 1 |
- 元素与集合的操作:
a | (1<<i) -> 把 i 插入到集合中
a & ~(1<<i) -> 把 i 从集合中删除
a & (1<<i) -> 判断 i 是否属于该集合(零不属于,非零属于)
- 集合之间的操作:
a 补 -> ~a
a 交 b -> a & b
a 并 b -> a | b
a 差 b -> a & (~b)
- Python中bin一个负数(十进制表示),输出的是它的原码的二进制表示加上个负号,巨坑。
- Python中整型在内存中是以补码的形式存在的,输出自然也是按照补码输出。
- Python中整型是不限制长度的不会超范围溢出。
所以为了获得负数(十进制表示)的补码,需要手动将其和十六进制数0xffffffff
进行按位与操作,再交给bin()
进行输出,得到的才是负数的补码表示。
练习题:
leetcode 习题 136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
尝试使用位运算解决此题。
"""
Input file
example1: [2,2,1]
example2: [4,1,2,1,2]
Output file
result1: 1
result2: 4
"""
class Solution:
def singleNumber(self, nums: List[int]) -> int:
n0 = nums[0]
for num in nums[1:]:
n0 = n0 ^ num
return n0
# your code here
异或操作有交换律定理,相当于将相同的数字先异或,两两异或就只剩0了,然后0再和最后的一个数字异或得到最终值。