请在 100 分钟内作答以下问题,请合理分配时间,挑选自己擅长的问题作答。
问题一
-
简述闭包、lambda 表达式以及装饰器之间的异同。
-
如果可以,请给出一个场景,常用其中一者而非另外两个。
-
请用其中一种实现单例模式。
# 异同
闭包:是在函数内部引用了一个变量且能够让里面的嵌套函数使用, 外面无法使用该变量.
lambda: 就是一个匿名函数, 在使用的过程当中不需要定义函数名.
装饰器: 也是闭包, 不过里面的变量需要传递进去, 一般时候. 这个变量也是可执行的函数.
三者之间, 闭包和装饰器十分类似, 或者说, 装饰器就是通过闭包实现.
闭包更倾向于对变量的局部复用.
装饰器倾向于对代码的多次复用.
lambda的实现方式和闭包类似, 但它大多时候只是一个比较方便的表达式.
# 场景:
lambda:通常我在使用map函数的时候搭配lambda,因为lambda的简便, 会让代码十分简洁.
闭包: 如果当前代码中有一个变量是经常使用的, 且不会变动的. 可以考虑封成一个闭包, 把变量写死在里面.
装饰器: 装饰器的使用场景很广. 当该代码段需要在另一段代码前置执行的时候, 都可以考虑用装饰器的方式装饰其他函数.
单例模式
装饰器:
闭包和装饰器实现单例模式比较简单, 装饰器内设置isFlag, 并进行判断. 当isFlag为最初状态则继续, 否则返回.
如果用lambda实现单例, 应该首先解决变量和判断问题. 最后根据状态返回空或一个lambda生成的表达式.
#闭包
def func():
name = 'python'
def inner():
print(name)
return inner
f = func() # f = func() = inner
f() # f() = inner
# 输出结果:python
判断是否是闭包
函数名.__closure__ 在函数是闭包函数时,返回一个cell元素;不是闭包时,返回None。
>>>> print(inner.__closure__)
# lambda 匿名函数
# 普通python函数
def func(a,b,c):
return a+b+c
print func(1,2,3)
# 返回值为6
# lambda匿名函数
f = lambda a,b,c:a+b+c
print f(1,2,3)
# 返回结果为6
# 装饰器
import time
def dec(fun):
def wrap():
start = time.time()
fun()
end = time.time()
a = end - start
print a
return wrap
实现单例:
#装饰器实现
def Singleton(cls):
_instance = {}
def _singleton(*args,**kwargs):
if cls not in _instance:
_instance[cls] = cls(*args,**kwargs)
return _instance[cls]
return _singleton
问题二
现有 N 个最大长度为 M 的字符串组成的数组 S,其中可能包含重复相同的字符串。请设
计算法,将数组 S 中的字符串进行去重操作,得到不含有相同字符串的字符串集合。并分
别分析算法时间复杂度。尽量设计低时间复杂度的算法。使用一种你熟悉的编程语言写一个
完整函数,用代码实现你的算法,如果用现成的数据结构,请对数据结构的实现加以描述分
析。
包含重复相同的字符串的两种情况:
对于列表S内的字符串, 可能存完全相同的字符串,需去重.
对于列表S内的字符串内的字符, 可能存在相同字符,需去重.
Python中:
情况1. 直接使用set函数去重.通过对比hash实现, 时间复杂度O(1).
情况2. 需要使用双循环. 时间负责度O(mn)
第一循环获取N个字符串.
第二次循环获取M个字符.
然后通过获取该字符第一个下标的方式完成去重.
如下:
def func(list):
for n in len(list-1)
set = list[n]
new_set = ''
for i in set:
index = set.find(i)
new_set = set[index]
list[n] = new_set
问题三
贪吃蛇因场景简单,易于上手,是一个非常经典的游戏。简单来说,贪吃蛇通过在方形棋盘
格上虚拟出蛇和食物的场景,玩家控制蛇的前进方向,蛇在“吃”到食物后变长,同时刷新
新的食物,如此往复,直到蛇头撞到障碍物,结束游戏。假设现在某公司需要制作一款网络
贪吃蛇游戏,而你是其中的服务端开发工程师,请根据如下要求完成服务端的设计并回答后
续问题:
1)游戏终端是浏览器;
2)游戏逻辑运行和数据存储在服务端;
3)以合适的方法用单主机支持 20 个连接。
1:选择你熟悉的语言、方法、框架实现该服务端,通过一定方法描述你的方案架构、运行
流程、必要的数据结构和数据流(方法包括但不限于文字描述、图表、代码及伪代码)。
2:阐述你的设计思路及你觉得程序难点在哪,给出这些部分的伪代码,并解释为什么重要
和为什么这么做。
3:以下问题请根据时间自行安排,按照问题 2 的方式,选择一个解答:
1)对于网络条件较差(包括丢包、带宽、延迟等)的情况下如何修改;
2)对于用户数量和服务主机没有任何假设的情况下如何修改;
3)如果多个用户在同一地图场景内进行游戏该如何修改。
采用Django框架完成该服务器.
必要的数据结构:
用户:
id, 头像(金币等) , 战绩.
蛇:
用户id, 长度, 状态(是否死亡)
食物:
数量(对应棋盘), 刷新时间.
流程:
用户打开浏览器进入该界面, 通过session获取到用户id. 从而显示对应的头像,战绩,金币等.
用户开始游戏, 创建棋盘, 初始化蛇的状态并随机分布等量食物.
开始比赛.
比赛结束, 保存该战局信息.
对于我来说, 该程序难点在于. 比赛的过程的处理.
用户的蛇的实时位置.
如果逻辑处理放在服务器上的话, 根据每个用户控制的蛇的对应棋盘所在点进行判断的话. 那么首先要解决的就是延时问题.
如果蛇每移动一个坐标都需要上传新的位置到服务器的话, 那么对于服务器来说也是一个不小的负担.
如果一定需要由后端处理该逻辑的话.
我觉得可以由方向来判断蛇的状态.
只获取蛇的朝向.
假设蛇的移动速度是固定的, 每秒1格.
当游戏开始时候, 初始化蛇. 并获取蛇所在的坐标,和默认方向.
每当蛇进行转弯的时候.
后端计算出来方向改变的时间. 在这段时间内超这个方向移动了多少格. 然后计算与边框的距离.距离小于0, 则蛇状态为false.
每当蛇的方向发生变化的时候, 都重新计算一下.
-
优化方面:
-
如果网络条件较差, 一方面可以将一部分逻辑放在前端判断.一方面可以减少用户请求次数.
-
如果多用户在同场景游戏, 数据库需要引入棋盘, 棋盘大小, 以及 每场游戏的战绩等. 多用户间互动,除了对棋盘边框进行判断之外. 还要对其他用户的蛇的身体进行判断. (类似于上面 自己蛇身体的单元格false)
-