版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Python程序员面试分类模拟3
简答题
1.有20个数组,每个数组有500个元素,并且是有序排列好的,现在如何
在这20*500个数中找出排名前500的数?
正确答案:
对于求lop,k的问题,最常用的(江南博哥)方法为堆排序方法。对于本题而
言,假设数组降序排列,可以采用如下方法:
(1)首先建立大顶堆,堆的大小为数组的个数,即20,把每个数组最大的
值(数组第•个值)存放到堆中。Python中heapq是小顶堆,通过对输入和输出
的元素分别取相反数来实现大顶堆的功能。
(2)接着删除堆顶元素,保存到另外一个大小为500的数组中,然后向大
顶堆插入删除的元素所在数组的下一个元素。
(3)重复第(1)、(2)个步骤,直到删除个数为最大的k个数,这里为500。
为了在堆中取出一个数据后,能知道它是从哪个数组中取出的,从而可以
从这个数组中取下一个值,可以设置一个数组,数组中带入每个元素在原数蛆
中的位置。为了便于理解,把题目进行简化:三个数组,每个数组有5个元素
且有序,找出排名前5的数.
importheapq
defgetTop(data):
rowSize=len(data)
columnSize=len(data[0])
result3=[None]*columnSizc
#保持一个最小堆,这个堆存放来自20个数组的最小数
heap二口
i=0
whilei<rowSize:
arr=(None,None,None)#数组设置三个变量,分别为数值,数值来源的数
组,数值在数组中的次序indox
arr=("data[i][0],i,0)
heapq.heappush(heap,arr)
i+=l
num=0
whilenum<columnSize:
#删除顶点元素
d二heapq.heappop(heap)
result3[num]=_d[0]
num+=l
if(num>=columnSize):
break
#将value置为该数原数组里的下一个数
arr=(-data[d[l]][d[2]+l],d[l],d[2]+l)
heapq.heappush(heap,arr)
returnresult3
if_name_二二〃_main_〃:
data=[[29,17,14,2,1],[19,17,16,15,6],[30,25,20,14,5]]
printgetTop(data)
程序的运行结果为:
3029252019
通过把ROWS改成20,COLS改成50,并构造相应的数组,就能实现题目的
要求。对于升序排列的数组,实现方式类似,只不过是从数组的最后一个元素
开始遍历。
[考点]如何找出排名前500的数
2.给定一个数组,已知这个数组中有大量的重复的数字,如何对这个数组进
行通效地排序?
万确答案:
如杲使用小规的排序方法,虽然最好的排序算法的时间复杂度为0(N10gJ),但
是使用常规排序算法显然没有用到数组中有大量重复数字这个特性。如何能使
用这个特性呢?下面介绍两种更加高效的算法。
方法一:AVL树
这种方法的主要思路为:根据数组中的数构建一个AVL树,这里需要对
AVL树做适当的扩展,在结点中增加一个额外的数据域来记录这个数字出现的次
数,在AVL树构建完成后,可以对AVL树进行中序遍历,根据每个结点对应数
字出现的次数,把遍历结果放回到数组中就完成了排序,实现代码如下:
#AVL树的结点
classNode:
def―init―(self,data):
seif.data=data
self.left=self.right=None
self,height=self.count=l
classSort:
#中序遍历AVL树,把遍历结果放入到数组中
definorder(self,arr,root,index):
ifroot!=None:
#中序遍历左子树
index=self,inorder(arr,root,left,index)
#把root结点对应的数字根据出现的次数放入到数组中
i=0
whilei<root.count:
arr[index]=root.data
index+=l
i+=l
并中序遍历右子树
index=self.inorder(arr,root,right,index)
returnindex
#得到树的高度
defgetHeight(self,node):
ifnode-None:
return0
plSP:
returnnode,height
并把以y为根的子树向右旋转
defrightRotate(self,y):
x=y.left
T2=x.right
#旋转
x.right=y
y.left=T2
y.height=max(self.getHeight(y.left),self.getHeight(y.right))+1
x.height=max(self.getHeight(x.left),self.getHeight(x.right))+1
并返回新的根结点
returnx
并把以x为根的子树向右旋转
defleftRotate(self,x):
y=x.right
T2=y.left
y.left二x
x.right=T2
x.height=max(self.getHeight(x.left),self.getHeight(x.right))+1
y.height=max(self.getHeight(y.left),self.getHeight(y.right))+1
#Returnnewroot
returny
#获取树的平衡因子
defgetBalance(self,N):
if(N==None):
return0
returnself.getHeight(N.left)-self.getHeight(N.right)
如果data在AVL树中不存在,则把data插入到AVL树中,否则把这个结
点对应的count加1即可
〃〃//
definsert(self,root,data):
ifroot==None:
return(Node(data))
#data在树中存在,把对应的结点的count加1
ifdata-root.data:
root.count+=l
rpt.urnroot.
#在左子树中继续查找data是否存在
ifdata<root.data:
root,left=self,insert(root,left,data)
#在右子树中继续查找data是否存在
else:
root.right=self.insert(root,right,data)
并插入新的结点后更新root结点的高度
root.height=max(self.getHeight(root,left),self.getHeight(root,ri
ght))+l
#获取树的平衡因子
balance=self.getBalance(root)
并如果树不平衡,根据数据结构中学过的四种情况进行调整
#LL型
ifbalance>1anddata<root.left,data:
returnself,rightRotate(root)
#RR型
elifbalance01anddata>root.right,data:
returnself.leftRotate(root)
#LR型
elifbalance>1anddata>root.left,data:
root.left=self.leftRotate(root,left)
returnself.rightRorate(root)
#RL型
elifbalance<-landdata<root.right,data:
root,right=self.rightRotate(root,right)
returnself.leftRotate(root)
returnroot
#使用AVL树实现排序
defsort(self,arr):
root=Nonc#根结点
n=len(arr)
i=0
whilei<n:
root=self.insert(root,arr[i])
i+=l
index=0
self,inorder(arr,root,index)
ifname_二〃_main_〃:
arr=[15,12,15,2,2,12,2,3,12,100,3,3]
s=Sort()
s.sort(arr)
whilei<len(arr):
printarr[i],
i+=l
代码运行结果为:
2223331212121515100
算法性能分析:
这种方法的时间复杂度为O(NLogJ),其中,N为数组的大小,M为数组中
不同数字的个数,空间复杂度为0(N)。
方法二:哈希法
这种方法的主要思路为创建一个哈希表,然后遍历数组,把数组中的数字
放入哈希表中,在遍历的过程中,如果这个数在哈希表中存在,则直接把哈希
表中这个key对应的value而1;如果这个数在哈希表中不存在,则直接把这个
数添加到哈希表中,并且初始化这个key对应的value为1。实现代码如下:
defsort(arr):
datacount=dict()
n=len(arr)
#把数组中的数放入map中
i=0
whilei<n:
ifstr(arr[i])indata_count:
data_count[str(arr[i])]=data_count.get(str(arr[i]))+1
else:
data_count[str(arr[i])]=1
i+=l
index=O
forkey,valueindata_count.items():
i二value
whilei>0:
arr[index]=key
index+=l
i-=l
if_name_二〃―main―〃:
arr=[15,12,15,2,2,12,2,3,12,100,3,3]
sort(arr)
i=0
whilei<len(arr):
printarr[i],
i+=l
算法性能分析:
这种方法的时间复杂度为0(N+MLogJ),空间复杂度为0(M)o
[考点]如何对有大量重复的数字的数组排序
3.求出用1,2,5这三个数不同个数组合的和为100的组合个数。为了更好
地理解题目的意思,下面给出几组可能的组合:100个1,0个2和0个5,它
们的和为100;50个1,25个2,。个5的和也是100;50个1,20个2,2个5
的和也为100o
正确答案:
嘉简单的方法就是对所有的组合进行尝试,然后判断组合的结果是否满足
和为100,这些组合有如下限制:1的个数最多为100个,2的个数最多为50
个,5的个数最多为20个。实现思路为:遍历所有可能的组合1的个数x(0V
=x<=100),2的个数y(0=VyV=50),5的个数z(0V=zV=20),判断x+2y+5z
是否等于100,如果相等,那么满足条件,实现代码如下:
defcombinationCount(n):
count=0
numl=n#1最多的个数
num2=n/2#2最多的个数
num5=n/5#5最多的个数
x=0
whilex<==numl:
y二0
whiley<=num2:
z=0
whilez<=num5:
ifx+2*y+5*z==n:#满足条件
count+=l
z+=l
y+=l
x+=l
returncount
if_name_二二“_main::
printcombinationCount(100)
程序的运行结果为:
541
算法性能分析:
这种方法循环的次数为101*51*21。
方法二:数字规律法
针对这种数学公式的运算,一般都可以通过找出运算的规律进而简化运算
的过程,对于本题而言,对x+2y+5z=100进行变换可以得到x+5z=100-2y。从这
个表达式可以看出,x+5z是偶数且x+5zV=100°因此,求满足x+2y+5z=100组
合的个数就可以转换为求满足“x+5z是偶数且x+5zV=100”的个数。可以通过
对z的所有可能的取值(0〈=zV=20)进行遍历从而计算满足条件的x的值。
当z二0时,x的取值为0,为4,…,100(100以内所有的偶数),个数为
(100+2)/2
当z=l时;x的取值为1,3,5,95(95以内所有的奇数),个数为
(95+2)/2
当z=2时,x的取值为0,2,4,90(90以内所有的偶数),个数为
(90+2)/2
当z二3时,x的取值为1,3,5,85(85以内所有的奇数),个数为
(85+2)/2
当zT9时,x的取值为5,3,1(5以内所有的奇数),个数为(5+2)/2
当z=20时,x的取值为0(0以内所有的偶数),个数为(0+2)/2
根据这个思路,实现代码如下:
defcombinationCount(n):
count=0
m=0
whilem<=n:
count+=(m+2)/2
m+=5
returncount
算法性能分析:
这种方法循环的次数为21。
[考点]如何组合1,2,5这三个数使其和为100
4.给定一个数组a[N],希望构造一个新的数组b[N],其中,
b[i]=a[0]*a[l]*-*a[N-l]/a[i]o在构造数组的过程中,有如下几点要求:
(a)不允许使用除法;
(b)要求0(1)空间复杂度和0(N)时间复杂度:
(c)除遍历计数器与a[N]、b[N]外,不可以使用新的变量(包括栈临时变
量、堆空间和全局静态变量等);
(d)请用程序实现并简单描述。
正确答案:
如果没有时间复杂度与空间复杂度的要求,算法将非常简单,首先遍历一遍数
组a,计算数组a中所有元素的乘积,并保存到一个临时变量tmp中,然后再遍
历一遍数组a并给数组赋值:b[i]=但是这种方法使用了一个临时变
量,因此,不满足题目的要求,下面介绍另外一种方法。
在计算b[i]的时候,只要将数组a中除了a[i]以外的所有值相乘即可。
这种方法的主要思路为:首先遍历一遍数组a,在遍历的过程中对数组b进行赋
{t:b[i]=a[i-l]*b[i-l],这样经过一次遍历后,数组b的值为
b[i]=a[0]*a[l]*-*a[i-l]o此时只需要将数组中的值b[i]再乘以
a[i+l]祐[i+2]*…实现方法为逆向遍历数组a,把数组后半段值的乘积
记录到b[0]中,通过b[i]与b[0]的乘积就可以得到满足题目要求的b[i],具
体而言,执行b[i]=b[i]*b[0](首先执行的目的是为了保证在执行下面一个计
算的时候,b[0]中不包含与b[i]的乘积),接着记录数组后半段的乘积到b[0]
中:b[0]*=b[0]*a[i]o
实现代码如下:
defcalculate(a,b):
b[0]=l
N=len(a)
i=l
whilei<N:
b[i]=b[i-l]*a[i-l]#正向计算乘积
i+=l
b[O]=a[N-l]
i=N-2
whilei>=l:
b[i]*=b[O]
b[O]*=a[i]#逆向计算乘积
i-=l
if_name_二="_main_〃:
a=[1,2,3,4,5,6,7,8,9,10]
b=[None]*len(a)
calculate(a,b)
i=0
whi1pi<1pn(h):
printb[i],
i+=l
程序的运行结果为:
362880018144001209600907200725760604800518400453600
403200362880
[考点]如何按要求构造新的数组
5.数组中有N+2个数,其中,N个数出现了偶数次,2个数出现了奇数次(这
两个数不相等),请用0(1)的空间复杂度,找出这两个数。注意:不需要知道具
体位置,只需要找出这两个数。
正确答案:
方法一:字典法
对于本题而言,定义一个字典,把数组元素的值作为key,遍历整个数
组,如果key值不存在,则将value设为1,如果key值已经存在,则翻转该值
(如果为0,则翻转为1;如果为1,则翻转为0),在完成数组遍历后,字典中
value为1的就是出现奇数次的数。
例如:给定数组二[3,5,6,6,5,7,2,2];
首先遍历3,字典中的元素为:{3:1};
遍历5,字典中的元素为:{3:1,5:1};
遍历6,字典中的元素为:{3:1,元1,6:1};
遍历6,字典中的元素为:{3:1,5:1,6:0};
遍历5,字典中的元素为{3:1,5:0,6:0);
遍历7,字典中的元素为(3:1,5:0,6:0,7:11;
遍历2,字典中的元素为(3:1,5:0,6:0,7:1,2:1);
遍历2,字典中的元素为{3:1,5:0,6:0,7:1,2:0);
显然,出现1次的数组元素为3和7。
实现代码如下:
defget2Num(arr):
ifarr==Noneorlen(arr)<1:
print〃参数不合理〃
return
dic=dict()
i=0
whilei<len(arr):
#dic中没有这个数字,说明第一次出现,value赋值为1
ifarr[i]notindie:
dic[arr[i]]=l
力当前遍历的值在die中存在,说明前面出现过,value赋值为0
else:
dic[arr[i]]=0
i+=l
fork,vindie.items():
ifv==l:
printint(k)
ifname_==z,main〃:
arr=[3,5,6,6,5,7,2,2]
get2Num(arr)
程序输出为:
3
性能分析:
这种方法对数组进行了一次遍历,时间复杂度为0(n)。但是申请了额外的
存储过程来记录数据出现的情况,因此,空间复杂度为0(n)。
方法二:异或法
根据异或运算的性质不难发现,任何一个数字异或它自己其结果都等于
0o所以,对于本题中的数组元素而言,如果从头到尾依次异或每一个元素•,那
么异或运算的结果自然也就是那个只出现奇数次的数字,因为出现偶数次的数
字会通过异或运算全部消掉。
但是通过异或运算,也仅仅只是消除掉了所有出现偶数次数的数字,最后
异或运算的结果肯定是那两个出现了奇数次的数异或运算的结果。假设这两个
出现奇数次的数分别为a与b,根据异或运算的性质,将二者异或运算的结果记
为c,由于a与b不相等,所以,c的值自然也不会为0,此时只需知道c对应
的二进制数中某一个位为1的位数N,例如,十进制数44可以由二进制0010
1100表示,此时可取N=2或者3,或者5,然后将c与数组中第N位为1的数进
行异或,异或结果就是a,b中一个,然后用c异或其中一个数,就可以求出另
外一个数了。
通过上述方法为什么就能得到问题的解呢?其实很简单,因为c中第N位
为1表示a或
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论