Python 面试
==================== 电话面试 ====================
What?
- 什么是Python?
- 什么是Python自省?
- 什么是PEP?
- 什么是pickling和unpick?
- 什么是Python装饰器?
- 什么是Python的命名空间?
- 什么是字典推导式和列表推导式?
- Lambda函数是什么?
- *Argos,**warthogs参数是什么?
- 什么是Pass语句?
- unittest是什么?
- 构造器是什么?
- doc string是什么?
- 负索引是什么?
- 模块和包是什么?
- 垃圾回收是什么?
- CSRF是什么?
How?
- 如何让你的程序更具可读性?
- Python是如何被解释的?
- 如何在Python中拷贝一个对象?
- 如何用Python删除一个文件?
- 如何将一个数字转换成一个字符串?
- Python是如何进行内存管理的?
- 如何实现duple和list的转换?
- Python里面如何生成随机数?
- 如何在一个function里面设置一个全局的变量
- Python如何实现单例模式?其他23种设计模式python如何实现?
- Deepcopy如何实现?
- 算法排序在最坏情况下如何优化?
- 如何判断单向链表中是否有环?
- 如何遍历一个内部未知的文件夹?
- 数据库如何分区、分表?
- 如何对查询命令进行优化?
- 如何理解开源?
- 如何用MVC/MTV的缓存?
- Mys的死锁是如何产生的?
- Sql注入是如何产生的,如何防止?
- xxs如何预防?
- 如何生成共享秘钥? 如何防范中间人攻击?
- 如何管理不同版本的代码?
Different?
- 数组和元组之间的区别?
- _new_和_init_的区别?
- Python中单下划线和双下划綫的区别?
- 浅拷贝与深拷贝的区别是?
- 使用装饰器的单例和使用其他方法的单例,在后续使用中,有何区别?
- 多进程与多线程的区别?
- select和epoll的区别?
- TCP和UDP的区别?边缘触发和水平触发的区别?
- HTTP连接:get和post的区别?
- varchar与char的区别?
- BTree索引和hash索引的区别?
- 在判断object是否是class的instances时,type和Constance函数的区别?
- primary key和unique的区别?
- ecb和cbc模式有什么区别?
- 对称加密与非对称加密的区别?
- staticmethod和装饰器的区别?
- Xrange和range的区别?
- deepcopy 和 copy的区别?
- os.path和sys.path的区别?
- 生成器(generator)与函数的区别?
- os与sys模块的区别?
- NoSQL和关系数据库的区别?
==================== 自我介绍 ====================
==================== 项目经历 ====================
[CMS]
上传图片 | pdf | xlsx
html 转 pdf
编辑器
二维码
excel 文件导入数据
下载
增删改查
QuerySet 的查询:按文字 | Q | 注意不能拖库 | 大于等于、小于等于
开启 | 关闭
通过 | 驳回
屏蔽
分页
筛选
排序
同步
抓取
表单
图表(表格|echarts)
模板中的变量/标签/过滤器
短信通知
通知栏推送
广告投放
弹窗
[API]
1 + n => 1 + 1
并行与并发
同步与异步
阻塞与非阻塞
RESTfull API
json和xml区别
XML:
(1)应用广泛,可扩展性强,被广泛应用各种场合;
(2)读取、解析没有JSON快;
(3)可读性强,可描述复杂结构。
JSON:
(1)结构简单,都是键值对;
(2)读取、解析速度快,很多语言支持;
(3)传输数据量小,传输速率大大提高;
(4)描述复杂结构能力较弱。
综合题:话题模块
综合题:课程评价模块
[H5]
[background]
==================== 随机问答 ====================
[python]
浅拷贝与深拷贝的区别是?
在python中,对象赋值实际上是对象的引用。浅拷贝,没有拷贝子对象,所以原始数据改变,子对象会改变,而深拷贝,包含对象里面的子对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变。
装饰器
Python装饰器是Python中的特有变动,可以使修改函数变得更容易。
闭包
一个能记住嵌套作用域变量值的函数,尽管作用域已经不存在。
GIL
在python的原始解释器CPython中存在着GIL(Global Interpreter Lock,全局解释器锁),因此在解释执行python代码时,会产生互斥锁来限制线程对共享资源的访问,直到解释器遇到I/O操作或者操作次数达到一定数目时才会释放GIL。
所以,虽然CPython的线程库直接封装了系统的原生线程,但CPython整体作为一个进程,同一时间只会有一个线程在跑,其他线程则处于等待状态。这就造成了即使在多核CPU中,多线程也只是做着分时切换而已。
[sql]
limit - 分页
JOIN(内连接 | 左链接 | 右链接)
varchar与char的区别?
char 长度是固定的,不管你存储的数据是多少他都会都固定的长度。而varchar则处可变长度但他要在总长度上加1字符,这个用来存储位置。所以在处理速度上char要比varchar快速很多,但是对费存储空间,所以对存储不大,但在速度上有要求的可以使用char类型,反之可以用varchar类型。
explain
mysql优化
索引
数据库索引原理
二叉排序树 - 平衡二叉树- B+树
memcached和redis的区别
(1)性能对比:由于Redis只使用单核,而Memcached可以使用多核,所以平均每一个核上Redis在存储小数据时比Memcached性能更高。而在100k以上的数据中,Memcached性能要高于Redis,虽然Redis最近也在存储大数据的性能上进行优化,但是比起Memcached,还是稍有逊色。
(2)内存使用效率对比:使用简单的key-value存储的话,Memcached的内存利用率高,而如果Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于Memcached。
(3)Redis支持服务器端的数据操作:Redis相比Memcached来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在Memcached里,你需要将数据拿到客户端来进行类似的修改再set回去。这大大增加了网络IO的次数和数据体积。在Redis中,这些复杂的操作通常和一般的GET/SET一样高效。所以,如果需要缓存能够支持更复杂的结构和操作,那么Redis会是不错的选择。
数据库会死锁吗,举一个死锁的例子,mysql 怎么解决死锁。
产生死锁的原因主要是:
系统资源不足。 进程运行推进的顺序不合适。 资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
互斥条件:一个资源每次只能被一个进程使用。
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
解决数据库死锁的方法:
重启数据库。 杀掉抢资源的进程。
[algorithm]
[system]
1、进程与线程的区别
(1)粒度性分析:线程的粒度小于进程。
(2)调度性分析:进程是资源拥有的基本单位,线程是独立调度与独立运行的基本单位,出了寄存器,程序计数器等必要的资源外基本不拥有其他资源。
(3)系统开销分析:由于线程基本不拥有系统资源,所以在进行切换时,线程切换的开销远远小于进程。
(4)关系:同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进行至少包括一个线程。
(5)地址空间:进程拥有一个完整的虚拟地址空间,不依赖于线程而独立存在;反之,线程是进程的一部分,没有自己的地址空间,与进程内的其他线程一起共享分配给该进程的所有资源。
比如:开个QQ,开了一个进程;开了迅雷,开了一个进程。在QQ的这个进程里,传输文字开一个线程、传输语音开了一个线程、弹出对话框又开了一个线程。所以运行某个软件,相当于开了一个进程。在这个软件运行的过程里(在这个进程里),多个工作支撑的完成QQ的运行,那么这“多个工作”分别有一个线程。所以一个进程管着多个线程。通俗的讲:“进程是爹妈,管着众多的线程儿子”。
2、进程的状态及其转换
运行态 | 阻塞态 | 就绪态
3、进程同步与互斥的区别
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。
简单地说:同步体现的是一种协作性,互斥体现的是一种排他性。
4、进程间的通信方式有哪些?
(1)管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
(2)有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
(3)信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
(4)消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(5)信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
(6)共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
(7)套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
5、作业(或进程)的调度算法有哪些?
(1)先来先服务(FCFS,First-Come-First-Served): 此算法的原则是按照作业到达后备作业队列(或进程进入就绪队列)的先后次序来选择作业(或进程)。
(2)短作业优先(SJF,Shortest Process Next):这种调度算法主要用于作业调度,它从作业后备队列中挑选所需运行时间(估计值)最短的作业进入主存运行。
(3)时间片轮转调度算法(RR,Round-Robin):当某个进程执行的时间片用完时,调度程序便停止该进程的执行,并将它送就绪队列的末尾,等待分配下一时间片再执行。然后把处理机分配给就绪队列中新的队首进程,同时也让它执行一个时间片。这样就可以保证就绪队列中的所有进程,在一给定的时间内,均能获得一时间片处理机执行时间。
(4)高响应比优先(HRRN,Highest Response Ratio Next): 按照高响应比((已等待时间+要求运行时间)/ 要求运行时间)优先的原则,在每次选择作业投入运行时,先计算此时后备作业队列中每个作业的响应比RP然后选择其值最大的作业投入运行。
(5)优先权(Priority)调度算法: 按照进程的优先权大小来调度,使高优先权进程得到优先处理的调度策略称为优先权调度算法。注意:优先数越多,优先权越小。
(6)多级队列调度算法:多队列调度是根据作业的性质和类型的不同,将就绪队列再分为若干个子队列,所有的作业(或进程)按其性质排入相应的队列中,而不同的就绪队列采用不同的调度算法。
6、死锁产生的原因,死锁产生的必要条件是什么,如何预防死锁,如何避免死锁,死锁定理?
死锁产生的原因:(1)竞争资源;(2)进程推进顺序不当。
死锁产生的必要条件:
(1)互斥条件:一个资源一次只能被一个进程所使用,即是排它性使用。
(2)不剥夺条件:一个资源仅能被占有它的进程所释放,而不能被别的进程强占。
(3)请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源要求,而该资源又已被其它进程占有,此时请求进程阻塞,但又对已经获得的其它资源保持不放。
(4)环路等待条件:当每类资源只有一个时,在发生死锁时,必然存在一个进程-资源的环形链。
预防死锁:破坏四个必要条件之一。
死锁的避免:银行家算法,该方法允许进程动态地申请资源,系统在进行资源分配之前,先计算资源分配的安全性。若此次分配不会导致系统从安全状态向不安全状态转换,便可将资源分配给进程;否则不分配资源,进程必须阻塞等待。从而避免发生死锁。
死锁定理:S为死锁状态的充分条件是:尚且仅当S状态的资源分配图是不可完全简化的,该充分条件称为死锁定理。
死锁的解除:
(1)方法1:强制性地从系统中撤消一个或多个死锁的进程以断开循环等待链,并收回分配给终止进程的全部资源供剩下的进程使用。
(2)方法2:使用一个有效的挂起和解除机构来挂起一些死锁的进程,其实质是从被挂起的进程那里抢占资源以解除死锁。
7、分段式存储管理、分页式存储管理,两个的区别?
分段式存储管理:分页存储管理是将一个进程的地址(逻辑地址空间)空间划分成若干个大小相等的区域,称为页,相应地,将内存空间划分成与页相同大小(为了保证页内偏移一致)的若干个物理块,称为块或页框(页架)。在为进程分配内存时,将进程中的若干页分别装入多个不相邻接的块中。
分页式存储管理:在分段存储管理方式中,作业的地址空间被划分为若干个段,每个段是一组完整的逻辑信息,如有主程序段、子程序段、数据段及堆栈段等,每个段都有自己的名字,都是从零开始编址的一段连续的地址空间,各段长度是不等的。
两者的区别:
1、页是信息的物理单位,分页是为了实现非连续的分配,以便解决内存的碎片问题,或者说分页是为了由于系统管理的需要。
2、页的大小固定是由系统确定的,将逻辑地址划分为页号和页内地址是由机器硬件实现的。而段的长度是不固定的,决定与用户的程序长度,通常由编译程序进行编译时根据信息的性质来划分。
3、分页式存储管理的作业地址空间是一维的,分段式的存储管理的作业管理地址空间是二维的。
8、页面置换算法有哪些?
(1)最佳置换算法(Optimal):即选择那些永不使用的,或者是在最长时间内不再被访问的页面置换出去。(它是一种理想化的算法,性能最好,但在实际上难于实现)。
(2)先进先出置换算法FIFO:该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。
(3)最近最久未使用置换算法LRU(Least Recently Used):该算法是选择最近最久未使用的页面予以淘汰,系统在每个页面设置一个访问字段,用以记录这个页面自上次被访问以来所经历的时间T,当要淘汰一个页面时,选择T最大的页面。
(4)Clock置换算法:也叫最近未用算法NRU(Not RecentlyUsed)。该算法为每个页面设置一位访问位,将内存中的所有页面都通过链接指针链成一个循环队列。当某页被访问时,其访问位置“1”。在选择一页淘汰时,就检查其访问位,如果是“0”,就选择该页换出;若为“1”,则重新置为“0”,暂不换出该页,在循环队列中检查下一个页面,直到访问位为“0”的页面为止。由于该算法只有一位访问位,只能用它表示该页是否已经使用过,而置换时是将未使用过的页面换出去,所以把该算法称为最近未用算法。
(5)最少使用置换算法LFU:该算法选择最近时期使用最少的页面作为淘汰页。
多线程与死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
产生死锁的原因:
一.因为系统资源不足。
二.进程运行推进的顺序不合适。
三.资源分配不当。
如何才能产生死锁
产生死锁的四个必要条件:
一.互斥条件:所谓互斥就是进程在某一时间内独占资源。
二.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
三.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
四.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
死锁的预防
打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。
一.打破互斥条件。即允许进程同时访问某些资源。但是,有的资源是不允许被同时访问的,像打印机等等,这是由资源本身的属性所决定的。所以,这种办法并无实用价值。
二.打破不可抢占条件。即允许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能立即被满足时,它必须释放所占有的全部资源,以后再重新申请。它所释放的资源可以分配给其它进程。这就相当于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会降低系统性能。
三.打破占有且申请条件。可以实行资源预先分配策略。即进程在运行前一次性地向系统申请它所需要的全部资源。如果某个进程所需的全部资源得不到满足,则不分配任何资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性地将所申请的资源全部分配给该进程。由于运行的进程已占有了它所需的全部资源,所以不会发生占有资源又申请资源的现象,因此不会发生死锁。
四.打破循环等待条件,实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。
[network]
TCP/IP 的体系结构
网络接口层|网际层IP|运输层(TCP或UDP)|应用层
讲一下TCP三次握手(及原因)和TCP四次分手(及原因)
TCP三次握手的原因:防止失效的连接
TCP四次分手的原因:等待服务器端发送还未传送的数据
TCP 滑动窗口
TCP 流量控制 与 TCP 拥塞控制
TCP和UDP的区别及其适用场景
首先说一下什么是TCP和UDP:
TCP是传输控制协议,提供的是面向连接、可靠的字节流服务。
UDP是用户数据报协议,是一个简单的面向数据报的运输层协议。
TCP和UDP的区别:
TCP面向连接的运输层协议,UDP无连接
TCP是可靠交付,UDP是尽最大努力交付
TCP面向字节流,UDP面向报文
TCP是点对点连接的,UDP一对一,一对多,多对多都可以
TCP适合用于网页,邮件等,UDP适合用于视频,语音广播等
TCP和UDP的适用场景:
整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。
当对网络通讯质量要求不高的时候,要求网络通讯速度能尽量的快,比如视频、广播等,这时就可以使用UDP。
HTTP 请求方法
GET 和 POST 的区别
1.参数
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在内容实体中。
GET 的传参方式相比于 POST 安全性较差,因为 GET 传的参数在 URL 中是可见的,可能会泄露私密信息。并且 GET 只支持 ASCII 字符,如果参数为中文则可能会出现乱码,而 POST
支持标准字符集。
2.安全
3.幂等性
4.可缓存
5.XMLHttpRequest
HTTP 状态码
200 请求成功
201 创建成功
400 请求错误
401 未验证
403 被拒绝 签名问题
404 无法找到
405 错误 – 方法不被允许 (Method not allowed)
409 资源冲突
499 “client has closed connection”。这很有可能是因为服务器端处理的时间过长,客户端“不耐烦”了。
500 服务器内部错误
502 Bad Gateway是指错误网关,无效网关
504 Gateway Timeout 网关超时,由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答。(HTTP 1.1新)。
Cookie
HTTP 协议是无状态的,主要是为了让 HTTP 协议尽可能简单,使得它能够处理大量事务。HTTP/1.1 引入 Cookie 来保存状态信息。
Cookie 是服务器发送给客户端的数据,该数据会被保存在浏览器中,并且客户端的下一次请求报文会包含该数据。通过 Cookie 可以让服务器知道两个请求是否来自于同一个客户端,从而实现保持登录状态等功能。
Session 和 Cookie 区别
Session 是服务器用来跟踪用户的一种手段,每个 Session 都有一个唯一标识:Session ID。当服务器创建了一个 Session 时,给客户端发送的响应报文包含了 Set-Cookie 字段,其中有一个名为 sid 的键值对,这个键值对就是 Session ID。客户端收到后就把 Cookie 保存在浏览器中,并且之后发送的请求报文都包含 Session ID。HTTP 就是通过 Session 和 Cookie 这两种方式一起合作来实现跟踪用户状态的,Session 用于服务器端,Cookie 用于客户端。
HTTP 和 HTTPS区别
HTTP 有以下安全性问题:
使用明文进行通信,内容可能会被窃听;
不验证通信方的身份,通信方的身份有可能遭遇伪装;
无法证明报文的完整性,报文有可能遭篡改。
HTTPs 并不是新协议,而是 HTTP 先和 SSL(Secure Sockets Layer)通信,再由 SSL 和 TCP 通信。也就是说 HTTPs 使用了隧道进行通信。通过使用 SSL,HTTPs 具有了加密、认证和完整性保护。
对称密钥加密 和 非对称密钥加密
- 对称密钥加密
对称密钥加密(Symmetric-Key Encryption),加密的加密和解密使用同一密钥。
优点:运算速度快;
缺点:密钥容易被获取。
- 公开密钥加密
公开密钥加密(Public-Key Encryption),也称为非对称密钥加密,使用一对密钥用于加密和解密,分别为公开密钥和私有密钥。公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。
优点:更为安全;
缺点:运算速度慢;
- HTTPs 采用的加密方式
HTTPs 采用混合的加密机制,使用公开密钥加密用于传输对称密钥,之后使用对称密钥加密进行通信。(下图中的 Session Key 就是对称密钥)
Web 攻击技术
- 主动攻击
直接攻击服务器,具有代表性的有 SQL 注入和 OS 命令注入。
- 被动攻击
设下圈套,让用户发送有攻击代码的 HTTP 请求,用户会泄露 Cookie 等个人信息,具有代表性的有跨站脚本攻击(XSS)和跨站请求伪造(CSRF)。
[oo]
MVC
MVC是Model—View—Controler的简称。即模型—视图—控制器。MVC是一种设计模式,它强制性的把应用程序的输入、处理和输出分开。MVC中的模型、视图、控制器它们分别担负着不同的任务。
视图: 视图是用户看到并与之交互的界面。视图向用户显示相关的数据,并接受用户的输入。视图不进行任何业务逻辑处理。
模型: 模型表示业务数据和业务处理,相当于JavaBean。一个模型能为多个视图提供数据。这提高了应用程序的重用性。
控制器: 当用户单击Web页面中的提交按钮时,控制器接受请求并调用相应的模型去处理请求,然后根据处理的结果调用相应的视图来显示处理的结果。
MVC的处理过程:首先控制器接受用户的请求,调用相应的模型来进行业务处理,并返回数据给控制器。控制器调用相应的视图来显示处理的结果。并通过视图呈现给用户。
[distribute]
[tool]
[program]
[综合]
概念
变量(动态语言|静态语言;浅拷贝与深拷贝;_|__;实例变量|类变量) - 函数(函数参数|闭包(函数作为返回值|嵌套作用域)|匿名函数|装饰器|) - 类(方法|元类) - 模块 - 包
函数参数:位置参数|默认参数(默认参数必须指向不变对象)|可变参数|关键字参数|命名关键字参数|参数组合(func(*args, **kw))
偏函数:当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
数据结构
list
list - 切片 - 列表生成式 - 生成器generator - yield - Iterator(迭代器)- Iterable(迭代对象)
mutable | immutable
对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而 list, dict, set 等则是可以修改的对象。(这就是这个问题的重点)
生成器:
第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
Xrange和range的区别
yield - Python对协程的支持是通过generator实现的。
协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。
进程与线程区别
(1)粒度性分析:线程的粒度小于进程。
(2)调度性分析:进程是资源拥有的基本单位,线程是独立调度与独立运行的基本单位,出了寄存器,程序计数器等必要的资源外基本不拥有其他资源。
(3)系统开销分析:由于线程基本不拥有系统资源,所以在进行切换时,线程切换的开销远远小于进程。
(4)关系:同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进行至少包括一个线程。
举例:QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。
死锁
编程
- 定义一个函数,其作用是检测字符串里所有 a 的索引位置,最终返回所有 index
def get_a_indexs(string):
result = []
for index, letter in enumerate(string):
if letter == 'a':
result.append(index)
return result
results = get_a_indexs('this is a test to check a')
results_list = list(results)
dict
哈希表的原理
普通字典 - 字典推导式(互换字典的键值对) - 有序字典 - 默认值字典
缓存(redis|memcache) - 分布式缓存
Redis与Memcached的区别与比较
-
Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。
-
Redis支持数据的备份,即master-slave模式的数据备份。
-
Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部存在内存之中
-
redis的速度比memcached快很多
-
Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的IO复用模型。
一致性哈希算法
解决:Hash 取模
问题:这个算法的容错性和扩展性都较差
优点:容错性|拓展性
问题: 当节点较少时会出现数据分布不均匀的情况
解决:这个问题,一致哈希算法引入了虚拟节点。将每一个节点都进行多次 hash,生成多个节点放置在环上称为虚拟节点:
增删改查
python - []
django(query_set) - save() | delete() | update() | filter()
sql - insert into | delete from | update | select
sql死锁
数据库索引原理:二叉排序树 - 平衡二叉树 - B+树
[一个查询问题]
- 查询
SELECT t.* FROM statstic.user_data t
WHERE created_at>='2018-04-23 00:00:00' and created_at<'2018-04-24 00:00:00'
order by created_at;
- 转化为 query_set
datas = Customer.objects.filter(create_time__gte=start_time, create_time__lte=end_time)
- 如果 create_time 是时间戳(timestamp与datetime的互转)
def timestamp_to_datetime(response):
return datetime.datetime.fromtimestamp(response)
def datetime_to_timestamp(d):
return int(time.mktime(d.timetuple()))
-
HTTP 请求方法 - POST | DELETE | PUT or PATCH | GET
-
ds - 栈
class Stack():
def __init__(st,size):
st.stack=[]
st.size=size
st.top=-1
def empty(st):
if st.top==-1:
return True
else:
return False
def full(st):
if st.top==st.size:
return True
else:
return False
def push(st,data):
if st.full():
print "Stack is full"
else:
st.stack.append(data)
st.top=st.top+1
def pop(st):
if st.empty():
print "Stack is empty"
else:
st.top=st.top-1
数据库的写入几种方式:页面 | 接口 | 爬虫 | excel
==================== 做编程题 ====================
[str]
- 去重
- ‘aaabbc’
- 统计
- ‘aaabbc’.count(‘b’)
- 反转
- s[::-1]
- 排序
- sorted(“hello”)
- 格式化字符串: format | %s | +
[list]
- 去重
-
[1,1,2,3,3]
-
[{“a”: 3},{“a”: 1},{“a”: 2},{“a”: 1},{“a”: 3}]
-
[{“a”: 3},{“a”: 1},{“a”: 2},{“a”: 1},{“a”: 3}] 按照 “a” 排序
- 统计
- [2,1,4,3,2].count(2)
- 反转
- s[::-1]
- 排序
- sorted(“hello”)
-
切割
-
索引(正 | 负)
[linked_list]
去重:83. Remove Duplicates from Sorted List (Easy)
反转:206. Reverse Linked List (Easy)
回文:234. Palindrome Linked List (Easy)
交点:160. Intersection of Two Linked Lists (Easy)
归并:21. Merge Two Sorted Lists (Easy)
[dict]
互换字典的键值对
[tree]
前 | 中 | 后 | 层次 遍历
[graph]
DFS | BFS
[综合]
统计问题
-
[“a”,“b”,“d”,“d”,“a”], 统计"a"出现的个数
-
[“a”,“b”,“d”,“d”,“a”], 统计每一个元素出现的个数
去重问题
-
[1,1,2,3,3]
-
[{“a”: 3},{“a”: 1},{“a”: 2},{“a”: 1},{“a”: 3}]
-
[{“a”: 3},{“a”: 1},{“a”: 2},{“a”: 1},{“a”: 3}] 按照 “a” 排序
链表去重
-
- Contains Duplicate
-
- Contains Duplicate II
-
- Contains Duplicate III
-
- 删除排序数组中的重复项
-
- 删除排序数组中的重复项 II
移除
-
- 移除元素
-
- 移除链表元素
-
- 删除链表的倒数第N个节点
反转
-
列表反转
-
列表回文
-
链表反转
-
链表回文
-
反转字典
-
- 翻转字符串里的单词
-
- 反转字符串中的单词 III
旋转
-
- 旋转数组
-
- 旋转链表
交集
-
- 两个数组的交集
-
- 两个数组的交集 II
-
- 相交链表
环点
-
- 环形链表
-
- 环形链表 II
合并
-
- 合并两个有序链表
-
- 合并两个有序数组
求和
-
- 两数之和
-
- 三数之和
-
- 四数之和
-
- 四数相加 II
-
- 两数相加 II
链表问题
链表:
1、找出单链表的倒数第K个元素(仅允许遍历一遍链表)
答:使用指针追赶的方法,定义一个fast指针和一个slow指针,fast指针先走K步,然后fast和slow同时继续走。当fast指针走到链表尾部时,slow指向的位置就是倒数第K个元素。注意:要考虑链表长度应该大于K。参考:剑指Offer(十四):链表中倒数第k个结点
2、找出单链表的中间元素(仅允许遍历一遍链表)
答:使用指针追赶的方法,定义一个fast指针和一个slow指针,两个指针同时走,fast指针每次走两步,slow指针每次走一步。当fast指针到链表尾部时,slow指针指向的就是链表的中间元素。
3、判断单链表是否有环?
答:使用指针追赶的方法,定义一个fast指针和一个slow指针,两个指针同时走,fast指针每次走两步,slow指针每次走一步。如果有环,则两者会相遇;如果没有环,fast指针会遇到NULL退出。
4、已知单链表有环,如何知道环的长度?
答:使用指针追赶的方法,定义一个fast指针和一个slow指针,两个指针同时走,fast指针每次走两步,slow指针每次走一步,找到碰撞点。然后使用slow指针,从该碰撞点开始遍历,绕着走一起圈,再次回到该点,所走过的结点数就是环的长度。
5、如何找到环的入口结点?
答:先使用题4的方法,计算出环的长度。然后重新从头结点开始遍历,定义一个fast指针和一个slow指针,fast指针先走l(环的长度)步,然后两个指针以相同的速度在链表上向前移动,直到它们再次相遇,那么这个相遇点即为环的入口结点。参考:剑指Offer(五十五):链表中环的入口结点
6、判断两个无环单链表是否相交?
答:一旦两个链表相交,那么两个链表从相交节点开始到尾节点一定都是相同的节点。所以,如果他们相交的话,那么他们最后的一个节点一定是相同的,因此分别遍历到两个链表的尾部,然后判断他们是否相同。
7、如何知道两个单链表(可能有环)是否相交?
答:根据两个链表是否有环来分别处理,若相交这个环属于两个链表共有
(1)如果两个链表都没有环,如题6所示方法。
(2)一个有环,一个没环,肯定不相交。
(3)两个都有环。在A链表上,使用指针追赶的方法,找到两个指针碰撞点,之后判断碰撞点是否在B链表上。如果在,则相交。
8、寻找两个相交链表的第一个公共结点。
答:我们也可以先让把长的链表的头砍掉,让两个链表长度相同,这样,同时遍历也能找到公共结点。此时,时间复杂度O(m+n),空间复杂度为O(MAX(m,n))。参考:剑指Offer(三十六):两个链表的第一个公共结点
9、反转链表。
答:我们使用三个指针,分别指向当前遍历到的结点、它的前一个结点以及后一个结点。在遍历的时候,交换当前结点的尾结点和前一个结点的。参考:剑指Offer(十五):反转链表指
数组问题
1、给定一个数组(非递减排序),同时给定一个目标数字,找出这个数字在该数组中第一次出现的位置,如果不存在,返回-1。例如[1,3,5,5,5,5,8,9,13,15],输入5,返回2,输入8,返回6,输入18,返回-1。
答:使用二分查找法即可。
2、给定一个数组,里面有很多数字(乱序),找出其中最大的4个数字。
答:最简单的办法就是先排序再找出最大的四数,这种方法时间复杂度过高。一个更好的方法是使用堆排序,即维护一个存储最大的4个数的最大堆。
解析:这的思想和代码可以参考《剑指Offer(二十九):最小的K个数》,这里仅仅做了一个变形。
3、给定一个整数的数组nums,返回相加为target的两个数字的索引值。假设每次输入都只有一个答案,并且不会使用同一个元素两次。
答:如果这个数组是已经排序的,可以使用头指针和为指针。如果是已经排序的,那么我们可以定义一个头指针left,一个为指针right。left指针指向元素值+right指针指向元素值的和为sum,用sum和target比较。如果sum大于target,说明和大了,那么right右指针左移一位,然后重新判断。反之,如果sum 小于target,说明和小了,那么left左指针右移以为,然后会从新判断。直到找到sum=target的情况。如果没有排序,可以使用使用哈希表,也就是散列表。
解析:如果没有排序,这道题就是Leetcode中的一道题。代码可以参考《Two Sum》。
4、给定一个字符串,找到最长无重复子字符串。
答:定义两个变量longest和left,longest用于存储最长子字符串的长度,left存储无重复子串左边的起始位置。然后创建一个哈希表,遍历整个字符串,如果字符串没有在哈希表中出现,说明没有遇到过该字符,则此时计算最长无重复子串,当哈希表中的值小于left,说明left位置更新了,需要重新计算最长无重复子串。每次在哈希表中将当前字符串对应的赋值加1。
解析:Leetcode中的一道题。代码可以参考《Longest Substring Without Repeating Characters》。
其他:
1、不使用现成的开根号库函数,如何实现开平方根的操作?
答:可以使用二分查找法或者牛顿法。
业务场景问题
如果给你1亿个数据,让你找出其中第1000大的数据,你会怎么做?我们先不考虑多进程和多线程,也不考虑数据库,如何在算法方面给出思路呢?
答:可以使用堆排序,创建一个存储1000个数据的小根堆。先将1亿个数据的前1000个数据放入这个小根堆中,然后继续遍历,对于新插入的数据,需要与小根堆的最小值进行比较,如果待插入的数据比这个最小值还小,那么不插入,如果比这个最小值大,那么就插入该数,并重新调整小根堆,随后继续使用此方法遍历整个数据。遍历一次数据后,就得到了前1000大的数据,然后输出小根堆的最小值,即根值,即可得到第1000大的数据。
解析:这道题当时能想到的就是用堆实现了,其他更好的方法欢迎探讨。