------------恢复内容开始------------
? 数值型 ? int、float、complex、bool ? 序列对象 ? 字符串 str ? 列 表 list ? tuple ? 键值对 ? 集合set ? 字典dict
? 数值型 ? int、float、complex、bool都是class,1、5.0、2+3j都是对象即实例 ? int:python3的int就是长整型,且没有大小限制,受限于内存区域的大小 ? float:由整数部分和小数部分组成。支持十进制和科学计数法表示。C的双精度型实现 ? complex:有实数和虚数部分组成,实数和虚数部分都是浮点数,3+4.2J ? bool:int的子类,仅有2个实例True、False对应1和0,可以和整数直接运算 ? 类型转换(built-in) ? int(x) 返回一个整数 ? float(x) 返回一个浮点数 ? complex(x)、complex(x,y) 返回一个复数 ? bool(x) 返回布尔值,前面讲过False等价的对象
? round(),四舍五入? ? math模块、floor()地板、天花板ceil() ? int() 、// ? 举例:
import math
print(math.floor(2.5), math.floor(-2.5))
print(math.ceil(2.5), math.ceil(-2.5))
----------------------------------------------
2 -3
3 -2
以下打印什么结果?说明什么
?
print(int(-3.6), int(-2.5), int(-1.4))
print(int(3.6), int(2.5), int(1.4))
print(7//2, 7//-2, -7//2, -(7//2))
print(2//3, -2//3, -1//3)
print(round(2.5), round(2.5001), round(2.6))
print(round(3.5), round(3.5001), round(3.6), round(3.3))
print(round(-2.5), round(-2.5001), round(-2.6))
print(round(-3.5), round(-3.5001), round(-3.6), round(-3.3))
---------------------------------------------------
-3 -2 -1
3 2 1
3 -4 -4 -3
0 -1 -1
2 3 3
4 4 4 3
-2 -3 -3
-4 -4 -4 -3
?
?round(),四舍六入五取偶 ?floor()向下取整、ceil()向上取整 ?int() 取整数部分 ?// 整除且向下取整
?min() ?max() ?pow(x,y) 等于x**y ?math.sqrt()
?进制函数,返回值是字符串 ?bin() ?oct() ?hex()
?math.piπ ?math.e自如常数
?type(obj) ,返回类型,而不是字符串 ?isinstance(obj, class_or_tuple),返回布尔值 ?举例:
type(a)
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name ‘a‘ is not defined
>>> type(‘abc‘)
<class ‘str‘>
>>> type(123)
<class ‘int‘>
>>> isinstance(6,str)
False
>>> isinstance(6,(str,bool,int))
True
>>> type(1+True)
<class ‘int‘>
>>> type(1+True+2.0)# 是什么?隐式转换
<class ‘float‘>
?一个队列,一个排列整齐的队伍 ?列表内的个体称作元素,由若干元素组成列表 ?元素可以是任意对象(数字、字符串、对象、列表等) ?列表内元素有顺序,可以使用索引 ?线性的数据结构 ?使用[ ] 表示 ?列表是可变的
?列表list、链表 ?queue、stack
?list() -> new empty list ?list(iterable) -> new list initialized from iterable‘s items ?列表不能一开始就定义大小 lst = list() lst = [] lst = [2, 6, 9, ‘ab‘] lst = list(range(5))
?索引,也叫下标 ?正索引:从左至右,从0开始,为列表中每一个元素编号 ?负索引:从右至左,从-1开始 ?正负索引不可以超界,否则引发异常IndexError ?为了理解方便,可以认为列表是从左至右排列的,左边是头部,右边是尾部,左边是下界,右边是上界 ?列表通过索引访问 ?list[index] ,index就是索引,使用中括号访问
?index(value,[start,[stop]]) ?通过值value,从指定区间查找列表内的元素是否匹配 ?匹配第一个就立即返回索引 ?匹配不到,抛出异常ValueError ?count(value) ?返回列表中匹配value的次数 ?时间复杂度 ?index和count方法都是O(n) ?随着列表数据规模的增大,而效率下降 ?如何返回列表元素的个数?如何遍历?如何设计高效? ?len()
?官方帮助文档 ?搜索关键字
?IPython中 ?help(keyword) ?keyword可以是变量、对象、类名、函数名、方法名
?索引访问修改 ?list[index] = value ?索引不要超界
?append(object) -> None ?列表尾部追加元素,返回None ?返回None就意味着没有新的列表产生,就地修改 ?时间复杂度是O(1) ?insert(index, object) -> None ?在指定的索引index处插入元素object ?返回None就意味着没有新的列表产生,就地修改 ?时间复杂度是O(n) ?索引能超上下界吗? ?超越上界,尾部追加 ?超越下界,头部追加
?extend(iteratable) -> None ?将可迭代对象的元素追加进来,返回None ?就地修改 ?+-> list ?连接操作,将两个列表连接起来 ?产生新的列表,原列表不变 ?本质上调用的是魔术方法add()方法 ?*-> list ?重复操作,将本列表元素重复n次,返回新的列表
?*-> list ?重复操作,将本列表元素重复n次,返回新的列表
x = [[1, 2, 3]]*3
print(x)
x[0][1] = 20
print(x)
y = [1]*5
y[0] = 6
y[1] = 7
print(y)
?
------------------------------
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
[[1, 20, 3], [1, 20, 3], [1, 20, 3]]
[6, 7, 1, 1, 1]
上面代码运行结果是什么?为什么?
? remove(value) -> None ? 从左至右查找第一个匹配value的值,移除该元素,返回None ? 就地修改 ? 效率? ? pop([index]) -> item ? 不指定索引index,就从列表尾部弹出一个元素 ? 指定索引index,就从索引处弹出一个元素,索引超界抛出IndexError错误 ? 效率?指定索引的的时间复杂度?不指定索引呢? ? clear() -> None ? 清除列表所有元素,剩下一个空列表
? reverse() -> None ? 将列表元素反转,返回None ? 就地修改 ? sort(key=None, reverse=False) -> None ? 对列表元素进行排序,就地修改,默认升序 ? reverse为True,反转,降序 ? key一个函数,指定key如何排序 ? lst.sort(key=function)
? in ? [3,4] in [1, 2, [3,4]] ? for x in [1,2,3,4]
列表复制 ? copy() -> List ? shadow copy返回一个新的列表
lst0 = list(range(4))
lst5 = lst0.copy()
print(lst5 == lst0)#True
lst5[2] = 10
print(lst5 == lst0)#Fulse
?
--------------------------------------
True
False
lst0和lst5一样吗? ? 对比左右程序的差别
lst0 = [1, [2, 3, 4], 5]
lst5 = lst0.copy()
lst5 == lst0
lst5[2] = 10
lst5 == lst0
lst5[2] = 5
lst5[1][1] = 20
lst5 == lst0
print(lst0,lst5)
--------------------------------------
[1, [2, 20, 4], 5] [1, [2, 20, 4], 5]
? shadow copy ? 影子拷贝,也叫浅拷贝,遇到引用类型,只是复制了一个引用而已 ? 深拷贝 ? copy模块提供了deepcopy
import copy
lst0 = [1, [2, 3, 4], 5]
lst5 = copy.deepcopy(lst0)
lst5[1][1] = 20
lst5 == lst0
? random模块 ? randint(a, b) 返回[a, b]之间的整数 ? choice(seq) 从非空序列的元素中随机挑选一个元素,比如random.choice(range(10)),从0到9中 随机挑选一个整数。random.choice([1,3,5,7]) ? randrange ([start,] stop [,step]) 从指定范围内,按指定基数递增的集合中获取一个随机数,基数 缺省值为1。 random.randrange(1,7,2) ? random.shuffle(list) ->None 就地打乱列表元素 ? sample(population, k) 从样本空间或总体(序列或者集合类型)中随机取出k个不同的元素,返回 一个新的列表 ? random.sample([‘a‘, ‘b‘, ‘c‘, ‘d‘], 2) ? random.sample([‘a‘, ‘a‘], 2) 会返回什么结果
? 求100内的素数 ? 从2开始到自身的-1的数中找到一个能整除的=》从2开始到自身开平方的数中找到一个能整除的 ? 一个合数一定可以分解成几个素数的乘积,也就是说,一个数如果能被一个素数整除就是合数 ? 计算杨辉三角前6行 ? 第n行有n项,n是正整数 ? 第n行数字之和为2n-1 只要求打印出杨辉三角的数字即可
求100内的素数 为了比较算法效率我们扩大到求100000内素数
import datetime
# 1 简单算法
# 一个数能被从2开始到自己的平发根的正整数整数整除,就是合数
start = datetime.datetime.now()
n = 100000
count = 0
for x in range(2, n):
for i in range(2, int(x ** 0.5) + 1):
if x % i == 0:
break
else:
count += 1
#print(x)
delta = (datetime.datetime.now() - start).total_seconds()
print(count) # 9592
print(delta) # 0.267015
print(‘-‘ * 30)
----------------------------------------------
2655287
0.680335
------------------------------
使用奇数:
start = datetime.datetime.now()
?
n = 100000
count = 1
for x in range(3, n, 2):
for i in range(3, int(x ** 0.5)+1, 2):
if x % i == 0:
break
else:
count += 1
#print(x)
delta = (datetime.datetime.now() - start).total_seconds()
print(count) # 9592
print(delta) # 0.132007
print(‘-‘ * 30)
--------------------------------------
1305035
0.35907
------------------------------
合数一定可以分解为几个质数的乘积,2是质数
质数一定不能整除1和本身之内的整数
start = datetime.datetime.now()
n = 100000
count = 1
primenumbers = [2]
for x in range(3, n, 2):
for i in primenumbers:
if x % i == 0:
break
else:
primenumbers.append(x)
count += 1
delta = (datetime.datetime.now() - start).total_seconds()
print(count) # 9592
print(delta) # 4.02523
print(‘-‘ * 30)
----------------------------------------
9592
4.569395
------------------------------
?
start = datetime.datetime.now()
n = 100000
count = 1
primenumbers = [2] # 质数列表
?
for x in range(3, n, 2):
flag = False # 不是素数
for i in primenumbers:
if i > int(x ** 0.5): # 素数
flag = True
break
if x % i == 0: # 合数
flag = False
break
if flag:
primenumbers.append(x)
count += 1
delta = (datetime.datetime.now() - start).total_seconds()
print(count) # 9592
print(delta) # 0.315018
----------------------------------------
9592
0.330924
------------------------------
算法2和算法4对比,算法2的奇数应该是多于算法4的,也就是算法4应该要快一点,但是测试的记过却不是,为什 么? 结果是增加了质数列表反而慢了,为什么? 修改算法如下
# 4 缩小范围
# x ** 0.5 在循环中只需计算一次
# 使用列表存储已有的质数,同时缩小范围
start = datetime.datetime.now()
n = 100000
count = 1
primenumbers = [2]
?
for x in range(3, n, 2): # 大于2质数只可能是奇数
flag = False # 不是素数
edge = int(x**0.5) # 计算一次
for i in primenumbers:
if i > edge: # 素数
flag = True
break
if x % i == 0: # 合数
flag = False
break
if flag:
primenumbers.append(x)
count += 1
delta = (datetime.datetime.now() - start).total_seconds()
print(count) # 9592
print(delta) # 0.106006
---------------------------------------------
9592
0.108905
-------------------------------------
这回测试,速度第一了。也就是增加了列表,记录了质数,控制了边界后,使用质数来取模比使用奇数计算更少。 空间换时间,使用列表空间存储质数列表,来换取计算时间。
孪生素数性质 大于3的素数只有6N-1和6N+1两种形式,如果6N-1和6N+1都是素数称为孪生素数
# 大于3的素数只有6N-1和6N+1两种形式,如果6N-1和6N+1都是素数称为孪生素数
# 注意,其实测试的都是6的倍数的前后的数字,这些数字一定是奇数
n = 100
count = 5 # 2, 3, 5
x = 7
step = 4
?
while x < n:
if x % 5 != 0:
print(x) # 打印出待测试的数
x += step
step = 4 if step == 2 else 2
由此,得到下面算法5
# 5 使用素数性质
# 大于3的素数只有6N-1和6N+1两种形式,如果6N-1和6N+1都是素数称为孪生素数
start = datetime.datetime.now()
n = 100000
count = 3 # 2, 3, 5
x = 7
step = 4
?
while x < n:
if x % 5 != 0:
for i in range(3, int(x**0.5)+1, 2):
if x % i == 0: # 合数
break
else:
count += 1
x += step
step = 4 if step == 2 else 2
delta = (datetime.datetime.now() - start).total_seconds()
print(count) # 9592
print(delta) # 0.122006
----------------------------------------------
9592
0.146466
----------------------------------------------
用了这个性质并没有超过算法4,原因还是在于使用列表来存储已经计算得到的素数来减少计算。请自行使用列表完成素数的存储。
第n行有n项,n是正整数
第n行数字之和为2**(n-1)
下一行依赖上一行所有元素,是上一行所有元素的两两相加的和,再在两头各加1
预先构建前两行,从而推导出后面的所有行
triangle = [[1], [1, 1]]
?
for i in range(2, 6):
cur = [1]
pre = triangle[i-1]
for j in range(i - 1):
cur.append(pre[j] + pre[j+1]) # 前一行2项之和
cur.append(1)
triangle.append(cur)
print(triangle)
变体 从第一行开始
triangle = []
n = 6
?
for i in range(n):
cur = [1]
triangle.append(cur)
?
if i == 0: continue
pre = triangle[i-1]
for j in range(i - 1):
cur.append(pre[j] + pre[j+1]) # 前一行2项之和
cur.append(1)
print(triangle)
除了第一行以外,每一行每一个元素(包括两头的1)都是由上一行的元素相加得到。如何得到两头的1呢?目标是打印指定的行,所以算出一行就打印一行,不需要用一个大空间存储所有已经算出的行。
for循环实现
n = 6
newline = [1] # 第一行是特例,因为0+0不等于1
print(newline)
?
for i in range(1, n):
oldline = newline.copy() # 浅拷贝并补0
oldline.append(0) # 尾部补0相当于两端补0
newline.clear() # 使用append,所以要清除
?
for j in range(i+1):
newline.append(oldline[j - 1] + oldline[j])
print(newline)
思路: 能不能一次性开辟空间,可以使用列表解析式或者循环迭代的方式。 能不能减少一半的数字计算。左右对称。
1、 构建行
triangle = []
n = 6
?
for i in range(n):
row = [1]
for k in range(i):
row.append(1) if k==i-1 else row.append(0)
triangle.append(row)
print(triangle)
上面创建每一行的代码过于啰嗦了,一次性创建出一行,以后覆盖其中数据就行了
triangle = []
n = 6
?
for i in range(n):
row = [1] * (i + 1) # 开辟速度快
triangle.append(row)
print(triangle)
2、 中点的确定
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
把整个杨辉三角看成左对齐的二维矩阵。
i==2时,在第3行,中点的列索引j==1
i==3时,在第4行,无中点
i==4时,在第5行,中点的列索引j==2
得到以下规律,如果有i==2j,则有中点
?
triangle = []
n = 6
?
for i in range(n):
row = [1] * (i + 1) # 一次开辟空间
triangle.append(row)
?
# i为0、1不进来,前两行进不来
# i为2,range(1,2),j取1
# i为3,range(1,2),j取1
# i为4,range(1,3),j取1 2
for j in range(1, i//2+1):
val = triangle[i-1][j-1] + triangle[i-1][j]
row[j] = val
row[-j-1] = val
?
print(triangle)
上面的代码row[-j-1] = val 多做了一次
triangle = []
n = 6
?
for i in range(n):
row = [1] * (i + 1) # 一次开辟空间
triangle.append(row)
# i为0、1不进来
# i为2,range(1,2),j取1
# i为3,range(1,2),j取1
# i为4,range(1,3),j取1 2
for j in range(1, i//2+1):
val = triangle[i-1][j-1] + triangle[i-1][j]
row[j] = val
if i != 2 * j:
row[-j-1] = val
?
print(triangle)
另一种中点的处理
i 中点索引 j
[1]
[1, 1]
[1, 2, 1] 2 1 or -2 0
[1, 3, 3, 1]
[1, 4, 6, 4, 1] 4 2 or -3 1
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1] 6 3 or -4 2
由此,得到中点的索引处i和j关系为i=2*(j+1)
其实,相当于上例中代码的j循环向左平移1,将所有的j变成 j+1
# 对称
triangle = [[1], [1, 1]] # 所有行
n = 10
for i in range(2, n): # 121
row = [1] * (i + 1) # 一次性开辟内存空间,效率更高
triangle.append(row)
?
for j in range(i//2): # i=4, range(2) => 0, 1
val = triangle[i-1][j] + triangle[i-1][j+1] # 1 3 3 1
row[j+1] = val
if i != 2*(j+1):
row[-(j+2)] = val # 有可能被重置
else: # i == 2*(j+1) 中点,n=7出现过3次中点
print(‘,,,,,‘, val)
print(triangle)
方法2每次都要清除列表,有点浪费时间。 能够用上方法3的对称性的同时,只开辟1个列表实现吗?
首先我们明确的知道所求最大行的元素个数,例如前6行的最大行元素个数为6个。 下一行等于首元素不变,覆盖中间元素。
n = 6
row = [1] * n # 一次性开辟足够的空间
print(row)
print(‘-‘ * 30)
for i in range(n):
print(row[:i+1])
运行结果如下
[1, 1, 1, 1, 1, 1]
------------------------------
[1]
[1, 1]
[1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1]
由于,这一次直接开辟了所有大小的列表空间,导致负索引比较难计算。 是否可以考虑直接使用正索引计算呢?
以第七行为例,索引1对称索引为5,而1 + 5 = 6当前索引值。
n = 6
row = [1] * n # 一次性开辟足够的空间
print(row)
print(‘-‘ * 30)
?
for i in range(n):
for j in range(i//2): # i为0,1不进入
val = row[j] + row[j+1]
row[j+1] = val
if i != 2 * (j+1):
row[i-(j+1)] = val
print(row[:i+1])
运行结果如下
[1, 1, 1, 1, 1, 1]
------------------------------
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 7, 4, 1]
[1, 5, 12, 12, 5, 1]
问题出在哪里了呢? 原因在于,4覆盖了3,导致3+3变成了3+4才有了7。使用一个临时变量解决
n = 6
row = [1] * n # 一次性开辟足够的空间
print(row)
print(‘-‘ * 30)
?
for i in range(n):
old = 1 # 相当于每行行首1,因为i从4开始就有覆盖了,引入这个变量
for j in range(i//2): # i为0,1不进入
val = old + row[j+1]
old = row[j+1]
row[j+1] = val
if i != 2 * (j+1):
row[i-(j+1)] = val
?
print(row[:i+1])
也可以写成下面这样
?
n = 6
row = [1] * n # 一次性开辟足够的空间
print(row)
print(‘-‘ * 30)
?
for i in range(n):
old = 1 # 相当于每行行首1,因为i从4开始就有覆盖了,引入这个变量
for j in range(i//2): # i为0,1不进入
# val = old + row[j+1]
# old = row[j+1]
# row[j+1] = val
row[j+1], old = old + row[j+1], row[j+1]
if i != 2 * (j+1):
row[i-(j+1)] = row[j+1]
print(row[:i+1])
--------------------------------------------
[1, 1, 1, 1, 1, 1]
------------------------------
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
------------恢复内容结束------------
原文:https://www.cnblogs.com/adaxi/p/12450122.html