1.数据结构与算法相关问题与解决技巧
一. 分割字符串问题
已知字符串"ab;cd|efg|hi,jk1|mn\topq;rst,uvw\txyz",
其中的',' ';' '|' '\t' 都是分割符,如何处理?
方法1、 连续使用str.split
s = "ab;cd|efg|hi,jk1|mn\topq;rst,uvw\txyz"def my_split(s, seps):res = [s]for sep in seps: t = []map(lambda ss: t.extend(ss.split(sep)), res)res = treturn resprint(my_split(s, ',;|\t'))
结果
['ab', 'cd', 'efg', 'hi', 'jk1', 'mn', 'opq', 'rst', 'uvw', 'xyz']
或者通过reduce
from functools import reducemy_split2 = lambda s, seps: reduce(lambda l, sep: sum(map(lambda ss: ss.split(sep), l), []), seps, [s])
print(my_split2(s, ',;|\t'))
结果
['ab', 'cd', 'efg', 'hi', 'jk1', 'mn', 'opq', 'rst', 'uvw', 'xyz']
此方法因为不方便阅读,所以不推荐
方法2、 正则表达式re.split方法(推荐)
import re
print(re.split('[;,|\t]+', s))
结果
['ab', 'cd', 'efg', 'hi', 'jk1', 'mn', 'opq', 'rst', 'uvw', 'xyz']
二. 如何在列表、字典、集合中根据条件筛选数据?
1. 过滤掉列表中的负数
使用列表解析方法
from random import randint# 生成一个10个随机数组成的数组
l = [randint(-10,10) for _ in range(10)]# 列表解析过滤掉负数
[x for x in l if x>=0]
使用filter
g = filter(lambda x: x>= 0, l) # filter会返回生成器对象
list(g) # g不能在调用next后再 用list
2. 找出分数大于90的学生
字典解析方法
# 创建一个班级的分数
d = {'student%d' %i: randint(50, 100) for i in range(1,21)}# 找到分数90分以上的同学
{k:v for k, v in d.items() if v>= 90}
使用filter
[filter(lambda item: item[1] >= 90, d.items())]
3. 留下集合中的3的倍数
s = {randint(0,20) for _ in range(20)}{x for x in s if x % 3 == 0}
三. 如何为元组中的每个元素命名,提高程序可读性?
实际案列
学生信息系统中数据为固定格式:(名字,年龄,性别,邮箱)('Jim', 16, 'male','jim8721@gmail.com')('LiLei', 17, 'male','leile@qq.com')('Lucy', 16, 'female','lucy123@yahoo.com')访问时,我们使用索引(index)访问,大量索引降低程序可读性
解决方案
方案一: 定义一系列数值常量或枚举类型
NAME, AGE, SEX, EMAIL = range(4) def xxx_func(student):if student[AGE] < 18:passif student[SEX] == 'male':passstudent = ('Jim', 16, 'male', 'jim8721@gmail.com')
xxx_func(student)
或者
from enum import IntEnumclass StudentEnum(IntEnum):NAME = 0AGE = 1SEX = 2EMAIL = 3print(student[StudentEnum.NAME])
print(student[StudentEnum.AGE])
print(student[StudentEnum.SEX])
print(student[StudentEnum.EMAIL])
运行结果:
Jim
16
male
jim8721@gmail.com
方案二: 使用标准库中 collections.namedtuple 替代内置tuple
from collections import namedtuple
Student = namedtuple('Student', ['name', 'age', 'sex', 'email'])s2 = Student('Jim', 16, 'male', 'jim8721@gmail.com')print(s2.name)
print(s2.age)
print(s2.sex)
print(s2.email)
运行结果
Jim
16
male
jim8721@gmail.com
四. 如何根据字典中值的大小,对字典中的项排序
实际案列
某班级英语成绩以字典形式存储为{'LiLei': 79,'Jim': 88,'Lucy': 92,...}如何根据成绩的高低,计算学生的排名?
解决方案
元组可以比较大小,所以
将字典中的各项转化为元组,使用列表内置函数sorted排序
方案1: 将字典中的项转化为(值,键)元组。
用列表解析
from random import randint
d = {k: randint(60,100) for k in 'abcdefgh'}l = [(v,k) for k,v in d.items()]print(sorted(l, reverse=True))
运行结果
[(99, 'c'), (96, 'f'), (83, 'b'), (80, 'a'), (69, 'h'), (69, 'g'), (64, 'd'), (60, 'e')]
用zip函数
from random import randint
d = {k: randint(60,100) for k in 'abcdefgh'}l = list(zip(d.values(), d.keys()))
print(sorted(l, reverse=True))
运行结果
[(99, 'c'), (96, 'f'), (83, 'b'), (80, 'a'), (69, 'h'), (69, 'g'), (64, 'd'), (60, 'e')]
方案2:传递sorted函数的key参数
sorted(d.items(), key=lambda item: item[1], reverse=True)
更新字典,加入成绩排名
p = sorted(d.items(), key=lambda item: item[1], reverse=True)# 把排名也加入字典中 每一项都变成 'h':(1, 99)
# 修改原字典
for i, (k,v) in enumerate(p, 1): # enumerate 第二个参数是起始值d[k] = (i, v)# 用新字典装
d2 = {k:(i,v) for i,(k,v) in enumerate(p, 1)}
五. 如何统计序列中元素的频度
实际案列
1. 某随机序列[12,5,6,4,6,5,5,7]中,找到出现次数最高的3个元素,他们出现的次数是多少?2. 对某英文文章的单词,进行词频统计,找到出现次数最高的10个单词,他们出现的次数是多少?
解决方案
方案1: 将序列转化为字典{元素: 频度}, 根据字典中的值排序
from random import randint
data = [randint(0,20) for _ in range(30)]d = dict.fromkeys(data, 0) # 生成一data中元素为 key的字典for x in data:d[x] += 1res = sorted(((v,k) for k,v in d.items()), reverse=True) # 生成器解析()比列表解析[]节省空间
print(res)
运行结果
[(5, 0), (3, 12), (3, 7), (2, 17), (2, 16), (2, 11), (2, 5), (2, 2), (2, 1), (1, 20), (1, 18), (1, 15), (1, 13), (1, 10), (1, 6), (1, 4)]
如果只是想取出最大的3个,可以使用堆代替排序后再取值的方法
import heapq
res2 = heapq.nlargest(3, ((v,k) for k,v in d.items()))
方案2: 使用标准库collections中的Counter对象
from collections import Counter
c = Counter(data) # 将数据列表传入,得到了频度字典
res3 = c.most_common(3) # 得到了频度最高的3个数
print(res3)
运行结果
[(20, 4), (14, 3), (10, 3)]
实际运用: 词频统计
from collections import Counter
import retxt = open('example.txt').read() # 读入文件
wordList = re.split('\W+', txt)
c2 = Counter(wordList)
res4 = c2.most_common(10) # 得到频率最高的10个单词
六. 如何快速找到多个字典中的公共键
西班牙足球队甲级联赛, 每轮球员进球统计:
第一轮:{'苏亚雷斯':1, '梅西':2, '本泽马':1, ...}
第二轮:{'苏亚雷斯':2, 'C罗':1, '格里兹曼':2, ...}
第三轮:{'苏亚雷斯':1, '托雷斯':1, '贝尔':1, ...}统计出前N轮,每场比赛都有进球的球员?思路:
找出每一轮的公共键
方法一: 利用列表解析式
from random import randint, sample# sample 取样函数
d1 = {k: randint(1, 4) for k in sample('abcdefgh', randint(3, 6))} # 第一轮
d2 = {k: randint(1, 4) for k in sample('abcdefgh', randint(3, 6))} # 第二轮
d3 = {k: randint(1, 4) for k in sample('abcdefgh', randint(3, 6))} # 第三轮dl = [d1, d2,d3]# 得到所有公共建
# python的all函数 全为真则返回true 还有any函数 有一个为真则true
[k for k in dl[0] if all(map(lambda d: k in d, dl[1:]))]
方法二: 利用集合的交集操作
- step1 使用字典的keys方法, 得到一个字典keys的集合
- step2 使用map函数, 得到每个字典keys的集合
- step3 使用reduce函数, 取所有字典的keys集合的交集
from functools import reduce
reduce(lambda a, b: a & b, map(dict.keys, dl)) # reduce(lambda a, b: a & b, map(lambda a: a.keys(), dl))
七. 如何让字典保持排序
实际案列
某编程竞赛系统, 对参赛选手编程阶梯进行计时, 选手完成题目后, 把该选手解题用时记录到字典中, 以便赛后按选手名查询成绩{'LiLei':(2, 43), 'HanMeimei':(5, 52}, 'Jim':(1, 39) ...}比赛结束后, 需要按排名顺序依次打印选手成绩, 如何实现?
解决思路
解决思路: 用有序字典代替无序字典使用标准库collections 中的OrderedDict
以OrderedDict代替内置字典Dict, 依次将选手成绩存入OrderedDict
from collections import OrderedDict# 模拟选手数据
players = list('abcdefgh')
from random import shuffle # 洗牌函数shuffle, 可以把次序打乱
shuffle(players)od = OrderedDict()
# 模拟得到按次序的字典
for i,p in enumerate(players, 1):od[p] = ifrom itertools import islice # 对原生迭代对象进行切片 可以用来对无法切片的字典进行切片def query_by_order(d, a, b=None):a -= 1if b is None:b=a+1return list(islice(od, a, b)) # 获取切片结果#获取第1名的player
query_by_order(od, 1)
八. 如何实现用户的历史记录功能(最多n条)
实际案列
很多应用程序都有浏览用户的历史记录功能, 列如:
1. 浏览器可以查看最近访问过的网页
2. 视频播放器可以查看最近播放过的视频文件
3. Shell可以查看用户输入过的命令现在我们制作一个简单的猜数字的小游戏,
如何添加历史记录功能, 显示用户最近猜过的数字?
小游戏代码
from random import randintdef guess(n, k):if n == k:print('猜对了, 这个数字是%d' % k)return Trueif n < k:print('猜大了, 比%d 小' % k)elif n> k:print('猜小了, 比%d 大' % k)return Falsedef main():n = randint(1, 100)i = 1while True:line = input('[%d] 请输入一个数字:' % i)if line.isdigit():k = int(line)i += 1if guess(n, k):breakelif line == 'quit':breakif __name__ == '__main__':main()
解决方案
使用容量为n的 队列存储历史记录
- 使用标准库collections中的deque, 它是一个双端循环队列
- 使用pickle模块将历史记录存储到硬盘, 以便下次启动使用(代替数据库)
from random import randint
from collections import dequedef guess(n, k):if n == k:print('猜对了, 这个数字是%d' % k)return Trueif n < k:print('猜大了, 比%d 小' % k)elif n > k:print('猜小了, 比%d 大' % k)return Falsedef main():n = randint(1, 100)i = 1hq = deque([], 5) # 初始化双端队列 []初始化数据 5 队列大小while True:line = input('[%d] 请输入一个数字:' % i)if line.isdigit():k = int(line)hq.append(k) # 记录i += 1if guess(n, k):breakelif line == 'quit':breakelif line == 'h?': # 查看历史记录print(list(hq))if __name__ == '__main__':main()
1.数据结构与算法相关问题与解决技巧相关推荐
- python 熊猫钓鱼_Python数据结构与算法之使用队列解决小猫钓鱼问题
本文实例讲述了Python数据结构与算法之使用队列解决小猫钓鱼问题.分享给大家供大家参考,具体如下: 按照<啊哈>里的思路实现这道题目,但是和结果不一样,我自己用一幅牌试了一下,发现是我的 ...
- 数据结构与算法 相关经典书籍推荐
如果计算机系只开三门课,那么这三门课就一定是:离散数学,数据结构与算法,编译原理 .如果只开一门课,那剩下的就一定是:数据结构与算法 . Niklaus Wirth说:算法+数据结构=程序,不说废话了 ...
- 【转】数据结构与算法(上)
数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.算法是为求解一个问题需要遵循的.被清楚指定的简单指令的集合.下面是自己整理的常用数据结构与算法相关内容,如有错误 ...
- 数据结构与算法 / 概念
@time 2019-07-15 @author Ruo_Xiao 一.概念 1.数据结构:一组数据的存储结构. 2.算法: 操作数据的一组方法. 3.二者的关系: (1)数据结构是为算法 ...
- c语言数据结构插入算法说明,C语言数据结构插入算法
C语言数据结构插入算法 C语言数据结构插入算法 C语言数据结构 数据结构学习 ->是二目运算符 p->a 引用了指针p指向的结构体的成员a. 整合 void unionL(List *La ...
- 数据结构中为什么输入数据还没输入完全就结束了_我岂能忍!面试官居然用数据结构和算法“羞辱”我...
如果大家是因为标题而进来,那我实话告诉你吧,真事!以后我会分享数据结构与算法相关的文章.为什么要学数据结构与算法,我总结了如下几点: 锻炼思维和问题处理能力 提高代码效率 大厂面试必备 情怀(大学没认 ...
- 从零学习数据结构与算法---基础与课前准备笔记
这里开始学习 数据结构与算法相关知识,这个主要是基于 极客时间 大佬 覃超老师的 算法训练营 和 王争老师的 数据结构与算法之美.这里再次感谢两位老师,下面文章内容主要是自己作为复习使用的笔记,如 ...
- PTA 数据结构与算法题目集(中文) 7-10 公路村村通 (30分) 最小生成树(kruskal算法)
我的GIS/CS学习笔记:https://github.com/yunwei37/ZJU-CS-GIS-ClassNotes <一个浙江大学本科生的计算机.地理信息科学知识库 > 还有不少 ...
- 【数据结构与算法】逆约瑟夫问题
约瑟夫问题可以说十分经典,其没有公式解也是广为人知的~ 目录 前言 一.约瑟夫问题与逆约瑟夫问题 1.约瑟夫问题 2.逆约瑟夫问题 二.思考与尝试(显然有很多失败) 问题分析 尝试一:递归/递推的尝试 ...
最新文章
- H5的学习从0到1-H5的实体(14)
- AAC规格分类和下载地址
- [Python爬虫] 中文编码问题:raw_input输入、文件读取、变量比较等str、unicode、utf-8转换问题
- “数据驱动、智能引领”,打造未来智能小镇“样板间”
- Activity生命周期Android,横屏切换不重新创建Activity, Activity的四种launchMode
- linux yum未找到命令,解决yum命令失效,vim: command not found
- 自学python要多久-自学Python多久能找到工作
- NTFS For Mac的兼容性问题
- H5前端框架说明文档
- 日语---之百度百科
- defer和async的区别
- 面向对象:结构化开发方法和面向对象开发方法
- UE4 蓝图接口 BluePrint Interface
- 色彩搭配 — 总结1
- Android之光线传感器
- 手机游戏软件开发的前景 The future of development of game software on mobiles
- 【720开发】 spring boot 快速入门
- html鼠标拖尾效果,JavaScript鼠标划过背景拖尾效果
- 【教学】MT4实现任意分钟变周期 灵活K线
- 动画的应用,西游记动画效果