整理了一些python面试可能遇到的题,提供给大家,希望能对大家有用!
1.下面的代码会输出什么?
def extend_list(val, list=[]): list.append(val) return list list1 = extend_list(10) list2 = extend_list(123,[]) list3 = extend_list('a') print(list1) print(list2) print(list3)
extend_list函数有两个参数,val和默认参数list,返回值为list
如果你认为输出的值为:[10],[123],[a];那你就上当了,这正是出题者想让你犯的错误。
正确答案是:[10, a],[123],[10, a];为什么呢?
关键点就在extend_list返回的值,它返回的是一个变量,绑定在一个固定的地址,list3传参之后改变了list,所以最后打印的时候,list1和list3的值相同。
那么为什么list2没变呢?因为list2传参的时候给传入了一个空的列表,list2所对应的list所绑定的地址发生了改变。
如果这样说你还不清楚的话,那么我借助代码来看一看。
def extend_list(val, list=[]): list.append(val) return list list1 = extend_list(10) print(list1) # [10] print(id(list1)) # 140427568644424 list2 = extend_list(123, []) print(list2) # [123] print(id(list2)) # 140427568644360 list3 = extend_list('a') print(list3) # [10, 'a'] print(id(list3)) # 140427568644424 print(list1) # [10, 'a'] print(list2) # [123] print(list3) # [10, 'a']
id(变量名) 可以查询变量所绑定的地址。
2.有一数组,从左到右渐增,从上到下渐增,给一个数字,判断它是否在这个数组中。
arr = [[1,4,7,10,15], [2,5,8,12,19], [3,6,9,16,22], [10,13,14,17,24], [18,21,23,26,30]] def getNum(num, data=None): while data: # 当data不为空,如果num大于data数组第1个元素的最后一项 # 删除此元素,再执行此比较 if num > data[0][-1]: del data[0] getNum(num, data=None) # 如果num小于此时的data数组第一个元素的最后一项 # 那么利用zip转换矩阵,将所有元素的最后一项都删除掉 # 然后再次用zip还原数组,回到第一步再次开始比较 elif num < data[0][-1]: data = list(zip(*data)) del data[-1] data = list(zip(*data)) getNum(num, data=None) # 如果num不大于也不小于此时data数组第一个元素的最后一项 # 那么num就是这一项,返回True else: return True # 当data为空时,num已经和原data数组比较完毕,且没有找到相同的数字 # 返回False return False # 如果是在当前文本打开,则执行print if __name__ == '__main__': print(getNum(18, arr))
3.求两个数的最大公约数、最小公倍数。
这个是送分题,我们可以用最笨的办法
def maxCommon(a, b):
# 两数的最大公因数最大为较小的数,所以我们遍历从1到较小的数 for i in range (1, b+1):
# 如果a和b除以i余数都为0,那么i就是a和b的公因数 if a % i == 0 and b % i == 0:
# 将i赋值给变量mx,因为i会从1到b,所以只要满足条件的i,都会对mx赋值
# 新值会替代旧值,所以最后返回的是最大公因数
mx = i return mx
print(maxCommon(36, 21)) # 3
这种笨办法我们称之为“穷举法”,既然有笨办法,那就有聪明的办法!
接下来我们就来看聪名的办法:欧几里得算法(碾转相除法),叫欧几里得算法显得高大上,碾转相除法贴切的多。
def modUntil(a, b): while b:
# 循环,序列赋值 a, b = b, a%b return a print(modUntil(36, 21)) # 3
这是什么鬼?代码怎么可以这么简洁?怎么就循环一直除一直除就可以得到最大公因数了?还除的是余数?
容老夫给你娓娓道来。
假设x,y有一最大公因数z,x和y都可以被z整除,那么对任意整数m和n,mx+ny也可以被z整除。
现在有x / y = q 余数为 w,那么x = qy + w,可知 x -qy = w,结合上一行可知 w 可以被z整除,也就是说,x除以y的余数可以被他俩的最大公因数整除。
循环到最后,a的值为上一循环时的余数,b的值为0。
是不是涨见识了?在欧几里得算法的基础上,有没有受到启发,有没有想到其它算法?
不吹不黑,我没想到,你如果想到了,那么你牛笔了。。。。
我们再来看下一种算法:尼考曼彻斯法(碾转相减法、更相减损术),如果你想到的也是这种算法,那么恭喜你,你的思维可以和尼考曼彻斯比肩了。
def deUntil(a, b): while a != b: if a > b: a = a - b else: b = b - a return b
不会又一脸懵逼了吧?碾转相除的道理还记得吗?两者一个道理,既然能除就能减,多减几次,剩下的等同于余数。。。
最大公约数的算法会了,那么最小公倍数就简单了
将两个数相乘再除以最大公约数就是最小公倍数,这里就不做演示了。