Python算法常用技巧与内置库

开发 后端 算法
近些年随着python的越来越火,python也渐渐成为了很多程序员的喜爱。许多程序员已经开始使用python作为第一语言来刷题。

 [[347377]]

python算法常用技巧与内置库

近些年随着python的越来越火,python也渐渐成为了很多程序员的喜爱。许多程序员已经开始使用python作为第一语言来刷题。

最近我在用python刷题的时候想去找点python的刷题常用库api和刷题技巧来看看。类似于C++的STL库文档一样,但是很可惜并没有找到,于是决定结合自己的刷题经验和上网搜索做一份文档出来,供自己和大家观看查阅。

1.输入输出:

1.1 第一行给定两个值n,m,用空格分割,第一个n决定接下来有n行的输入,m决定每一行有多少个数字,m个数字均用空格分隔.

解决办法:python的input函数接收到的输入默认都是字符串,所以我们使用 字符串切割、强制类型转换、列表生成器就可以完美解决输入问题。代码如下: 

  1. # 接收两个值,使用n,m分别接收列表中的两个值  
  2. n, m  = [int(x) for x in input().split()]  
  3. # 构造输入列表的列表  
  4. num_list = []  
  5. for i in range(n):  
  6.     # python可以不用在意m的值,将所有数值接收进来然后使用len判断长度  
  7.     tmp_list = [int(x) for x in input().split()]  
  8.     num_list.append(tmp_list) 

同理,若是用逗号(,)分隔的话,split函数中传入相同的值就行。

1.2 输出一行数字

由于python的print函数默认利用换行作为结束符,所以我们需要将它修改成我们需要的间隔,代码如下: 

  1. for i in range(10):  
  2.     print(i, end=' '

end是print函数中的一个参数,决定输出的结束字符,这里修改成空格代表输出一行数字,用空格间隔,其它字符可以自行修改。

2.空列表生成,字符串修改,列表遍历

2.1 代码编写过程中,有时候会需要一个带有长度的,有初始值的空列表,生成方式如下: 

  1. # 1. 用乘法生成一个初始值为False的长度为100的一维列表  
  2. visited = [False] * 100  
  3. # 2. 利用列表生成器生成一个n*m的二维的初始值为0的列表  
  4. visited = [[0 for i in range(m)] for j in range(n)] 

2.2 在python当中字符串是无法原地修改的,如果每次修改都生成一个新字符串,那么对修改次数很多且字符串很当的情况,开销是很大的。所以一般是把字符串转为列表进行修改最后再转回来。 

  1. string = 'I love to eat chicken'  
  2. # 将字符串转换成列表  
  3. string_list = list(string)  
  4. # .......对字符串列表进行修改  
  5. # Code  
  6. # 将字符串列表重新拼接成字符串  
  7. #string = ''.join(string_list) 

2.3 python中列表遍历有许多种不同的方式,最直接的办法是直接对列表进行迭代遍历,但是因为我们往往是基于索引对数组进行操作且需要修改数组的值,所以更推荐用以下代码中的第二三中办法: 

  1. num_list = [i for i in range(10)]  
  2. # 1. 直接迭代列表  
  3. for item in num_list:  
  4.     # Code  
  5.     pass  
  6. # 2. 通过索引进行迭代  
  7. for i in range(len(num_list)):  
  8.     print(num_list[i])  
  9. # 3. 通过enumerate函数进行迭代  
  10. for index, value in enumerate(num_list):  
  11.     # index为当前元素的索引,value为当前元素的值  
  12.     print(index, value) 

3. collections库的使用

3.1 deque队列

deque 是python中的队列(FIFO先进先出),队列在进行队首弹出的时候会比list要快。

尤其在使用BFS(深度优先搜索)的时候,队列是必须要使用到的。部分deque使用代码如下: 

  1. from collections import deque  
  2. # 初始化一个最大长度为3的队列  
  3. d = deque([1,2,3], maxlen=3 
  4. # 因为初始化队列最大长度为3,再添加元素会把队头元素挤出  
  5. d.append(4)  
  6. # 初始化一个不限制长度的队列  
  7. d = deque()  
  8. # 添加元素到队尾部  
  9. d.append(1)  
  10. d.append(2)  
  11. d.append(3)  
  12. # 将队首的元素弹出返回  
  13. print(d.popleft())  
  14. # 弹出队尾元素并返回值  
  15. print(d.pop())  
  16. # 在队首插入元素  
  17. d.appendleft(0) 

3.2 Counter计数器

Counter 是一个计数器,可以对一个序列计数,计算序列中某个元素出现的数量。

以下是示例代码: 

  1. import collections  
  2. # 一共有三种初始方法  
  3. # 1. 传入一个序列  
  4. print(collections.Counter(['a', 'b', 'c', 'a', 'b', 'b']))  
  5. # 2.传入一个字典 
  6. print(collections.Counter({'a':2, 'b':3, 'c':1}))  
  7. # 3.直接利用=传参  
  8. print(collections.Counter(a=2b=3c=1))  
  9. # 也可以无参数构造,利用update函数更新  
  10. c = collections.Counter()  
  11. print('Initial :', c)  
  12. # Initial: Counter()  
  13. c.update('abcdaab')  
  14. print('Sequence:', c)  
  15. # Sequence: Counter({'a': 3, 'b': 2, 'c': 1, 'd': 1})  
  16. c.update({'a':1, 'd':5})  
  17. print('Dict:', c)  
  18. # Dict: Counter({'d': 6, 'a': 4, 'b': 2, 'c': 1})  
  19. # 可以通过访问字典的访问方式访问Counter对象  
  20. for letter in 'abcde': 
  21.      print('%s : %d' % (letter, c[letter]))  
  22. # elements()方法可以返回一个包含所有Counter数据的迭代器  
  23. c = collections.Counter('extremely')  
  24. c['z'] = 0  
  25. print(list(c.elements()))  
  26. # ['e', 'e', 'e', 'm', 'l', 'r', 't', 'y', 'x']  
  27. # most_common()返回前n个最多的数据  
  28. c=collections.Counter('aassdddffff')  
  29. for letter, count in c.most_common(2):  
  30.     print('%s: %d' % (letter, count))  
  31. # f: 4  
  32. # d: 3  
  33. # Counter对象可以进行加减交并,直接使用运算符 +、-、&、|  
  34. # +会将两个字典中相同字符的出现次数相加,-会给出第一个Counter相对于第二个的差集。交集给出两个计数器当中都有的元素,且计数被赋值为较小的那个,并集为两个计数器的元素出现最多的那个。  
  35. c1 = collections.Counter(['a', 'b', 'c', 'a', 'b', 'b'])  
  36. c2 = collections.Counter('alphabet')  
  37. print ('C1:', c1)  
  38. print ('C2:', c2)  
  39. print ('\nCombined counts:') 
  40. print (c1 + c2)  
  41. print ('\nSubtraction:')  
  42. print (c1 - c2)  
  43. print ('\nIntersection (taking positive minimums):')  
  44. print (c1 & c2) 
  45. print ('\nUnion (taking maximums):')  
  46. print (c1 | c2)  
  47. # 以下为输出:  
  48. C1: Counter({'b': 3, 'a': 2, 'c': 1})  
  49. C2: Counter({'a': 2, 'l': 1, 'p': 1, 'h': 1, 'b': 1, 'e': 1, 't': 1})  
  50. Combined counts:  
  51. Counter({'a': 4, 'b': 4, 'c': 1, 'l': 1, 'p': 1, 'h': 1, 'e': 1, 't': 1})  
  52. Subtraction:  
  53. Counter({'b': 2, 'c': 1})  
  54. Intersection (taking positive minimums):  
  55. Counter({'a': 2, 'b': 1})  
  56. Union (taking maximums):  
  57. Counter({'b': 3, 'a': 2, 'c': 1, 'l': 1, 'p': 1, 'h': 1, 'e': 1, 't': 1}) 

3.3 defaultdict——带有默认值的字典

一般情况下创建的字典dict是不含有默认值的,即若是字典中不包含a这个key,调用dct{a}的话就会报错。

在进行算法设计和数据结构设计的时候我们希望任意给定一个key都能从字典中取出值来,哪怕只是一个默认值,这个时候我们就需要用到defaultdict。

例如在用字典表示图中一个节点的相连节点的时候,我们希望将这个节点作为一个key,然后与它相连的节点组成一个列表作为它的value,这个时候我们就可以使用defaultdict(list)来创建一个默认值为列表的字典。 

  1. # list的默认值为空列表  
  2. list_dict = collections.defaultdict(list)  
  3. # int的默认值为0  
  4. int_dict = collections.defaultdict(int)  
  5. print(list_dict['a']) 
  6. print(int_dict['a'])  
  7. # 输出:[]  
  8. # 输出:0 

3.4 小结

collection中常被用来写算法和数据结构的就是这几个,其它比如排序字典和命名元组很少会用上。

4.排序

4.1 对列表排序

对列表排序有两种方法,一种是使用列表内置的sort函数,sort函数直接在列表原地修改,无返回值,可以通过参数key自定义比较的key和比较函数。

第二种就是使用python的sorted函数,这个函数自由度比较高,可以自己设定比较函数和比较的key,返回一个新的列表。

如果需要自定义比较的函数,需要从库functools导入函数cmp_to_key函数,将比较函数转为key,使用代码如下: 

  1. def custom_sort(x,y):  
  2.     if x>y:  
  3.         # 返回-1代表需要排在前面  
  4.         return -1  
  5.     if x<y:  
  6.         # 返回1代表需要排在后面  
  7.         return 1  
  8.     return 0  
  9. lst = [i for i in range(10, -1, -1)]  
  10. print(lst) 
  11. lst.sort()  
  12. print(lst)  
  13. print(sorted(lst, key=cmp_to_key(custom_sort)))  
  14. # 输出如下:  
  15. # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]  
  16. # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  
  17. # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 

4.2 对字典/元组列表排序

若是需要对字典(将字典利用item函数转化成元组列表)或者元组列表这种每一个item有两个值的序列进行排序,这个时候就需要利用sorted函数中的key来决定取哪个值排序。代码如下: 

  1. # 利用字符串创建计数器字典  
  2. d = dict(collections.Counter('Hello World'))  
  3. print(d)  
  4. # 排序  
  5. print(sorted(d.items(), key=lambda x: x[1], reverse=True))  
  6. # 输出如下:  
  7. # {'H': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'W': 1, 'r': 1, 'd': 1}  
  8. # [('l', 3), ('o', 2), ('H', 1), ('e', 1), (' ', 1), ('W', 1), ('r', 1), ('d', 1)] 

5.排列组合

python内置的模块itertools中集成了一些与迭代有关的函数,其中就有排列组合函数。

5.1 排列

排列函数permutations接收一个列表,返回这个列表内所有元素的全排列列表。 

  1. from itertools import permutations  
  2. print(list(permutations([1,2,3])))  
  3. # 输出如下:  
  4. # [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)] 

5.2 组合

组合函数combinations接收两个参数,第一个为一个需要进行组合的列表,第二个参数为一个正整数,代表从列表中抽取多少个元素进行组合,返回一个组合列表。 

  1. from itertools import combinations  
  2. print(list(combinations([1,2,3],2)))  
  3. # 输出如下:  
  4. # [(1, 2), (1, 3), (2, 3)] 

6.小技巧

6.1 在python中分了可变类型和不可变类型,当函数传参的时候:

  •  若是不可变类型如字符串,则传递参数的时候会深拷贝一份,在新的数据上修改并不改变原数据
  •  若是可变类型如列表,则传递参数的时候传递的是引用,属于浅拷贝,在函数中对新列表进行操作会影响到原来的列表。

若是确实需要传递可变类型进入函数,则可以在函数内部第一行进行一次深拷贝如: 

  1. def test(num_list:list):  
  2.     # 进行深拷贝  
  3.     num_listnum_list = num_list[:] 

6.2 当删除列表中的元素的时候,列表后面的元素会自动往前移动,导致出错

例如,列表为[1,2,3,4,5,6],想要删除列表中的偶数,如果直接找到一个偶数然后利用其索引删除,如下代码所示(错误示范),那么很抱歉,出问题了。 

  1. # 此处为错误示范!!!!!!!!  
  2. lst = [1, 2, 3, 4, 5, 6]  
  3. for i in range(len(lst)):  
  4.     if lst[i] % 2 == 0:  
  5.         lst.pop(i)  
  6. print(lst)  
  7. # 上面这段代码没有输出,因为报索引越界错误了。 

下面的代码才是正确示范: 

  1. lst = [1, 2, 3, 4, 5, 6]  
  2. lst = [i for i in lst if i % 2 != 0]  
  3. print(lst)  
  4. # 输出如下:  
  5. # [1, 3, 5] 

若是需要更复杂的筛选手段,可以在if i%2 !=0那里更改成一个函数判断,函数内部就实现筛选方法。

6.3 访问字典元素要使用get方法

前文说过,普通的dict字典是没有默认值的,所以这个时候如果直接利用中括号放置key来查找value的话是有可能会报错的。

那么为了避免这种情况,在利用字典的key来取value的时候,需要利用字典的get函数。

get函数的第一个参数为key,第二个参数为可选(默认为None),当字典中找不到传入的key的时候,会返回第二个参数所赋的值。

7.小结

以上是本人在使用python刷题的时候作的一些总结,若有不到位的地方请指出。

本文旨在为自己做一个文档,同时也为大家提供一些便利。

关注我的公众号【程序小员】,收货一大波福利知识。

我是落阳,谢谢你的到访。 

 

责任编辑:庞桂玉 来源: segmentfault
相关推荐

2010-03-22 10:27:28

Python常用模块I

2021-07-26 08:31:10

CPP算法容器技巧

2016-10-20 20:21:09

Python爬虫技巧

2016-10-21 14:35:52

Pythonwebget方法

2017-04-27 10:38:28

排序算法比较分析

2011-09-02 10:06:51

OracleSqlLoad常用技巧

2021-03-16 10:12:24

python内置函数

2023-04-27 09:13:20

排序算法数据结构

2020-07-31 08:07:54

Python开发数据库

2010-03-04 10:16:41

Python应用技巧

2020-02-23 23:29:07

Python编程开发

2010-03-03 13:12:56

Python图像处理

2024-01-24 13:14:00

Python内置函数工具

2023-11-24 11:11:08

Python数据库

2022-04-25 13:11:14

Python编程技巧

2019-02-18 15:05:16

Python内置函数索引

2011-02-25 15:31:19

MySQL数据库DBA

2021-09-28 14:40:03

Python内置库itertools

2020-06-04 10:49:53

Pandas字符串技巧

2011-07-01 16:05:22

SEO
点赞
收藏

51CTO技术栈公众号