python面试题五:Python 编程
阅读原文时间:2023年07月09日阅读:2

1.B Tree和B+ Tree的区别?

1.B树中同一键值不会出现多次,并且有可能出现在叶结点,也有可能出现在非叶结点中。
而B+树的键一定会出现在叶结点中,并有可能在非叶结点中重复出现,以维持B+树的平衡。
2.因为B树键位置不定,且在整个树结构中只出现一次,

2.请列举常见排序并通过代码实现任意三种。

3.请列举常见查找并通过代码实现任意三种。

4.台阶问题/斐波那契

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

def memo(func):
cache = {}
def wrap(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrap

@memo
def fib(i):
if i < 2:
return 1
return fib(i-1) + fib(i-2)

5.变态台阶问题

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

fib = lambda n: n if n < 2 else 2 * fib(n - 1)

6.矩形覆盖

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

2*n个矩形的覆盖方法等于第2*(n-1)加上第2*(n-2)的方法。

f = lambda n: 1 if n < 2 else f(n - 1) + f(n - 2)

7.杨氏矩阵查找

在一个m行n列二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

def get_value(l, r, c):
return l[r][c]

def find(l, x):
m = len(l) - 1
n = len(l[0]) - 1
r = 0
c = n
while c >= 0 and r <= m: value = get_value(l, r, c) if value == x: return True elif value > x:
c = c - 1
elif value < x:
r = r + 1
return False

8.去除列表中的重复元素

list(set(l))

l1 = ['b','c','d','b','c','a','a']
l2 = []
[l2.append(i) for i in l1 if not i in l2]

9.链表成对调换

1->2->3->4转换成2->1->4->3.

class ListNode:
def __init__(self, x):
self.val = x
self.next = None

class Solution:
# @param a ListNode
# @return a ListNode
def swapPairs(self, head):
if head != None and head.next != None:
next = head.next
head.next = self.swapPairs(next.next)
next.next = head
return next
return head

10.创建字典的方法

items=[('name','earth'),('port','')]
dict2=dict(items)
dict1=dict((['name','earth'],['port','']))

11.合并两个有序列表

循环算法

思路:

定义一个新的空列表

比较两个列表的首个元素

小的就插入到新列表里

把已经插入新列表的元素从旧列表删除

直到两个旧列表有一个为空

再把旧列表加到新列表后面

def loop_merge_sort(l1, l2):
tmp = []
while len(l1) > 0 and len(l2) > 0:
if l1[0] < l2[0]:
tmp.append(l1[0])
del l1[0]
else:
tmp.append(l2[0])
del l2[0]
tmp.extend(l1)
tmp.extend(l2)
return tmp

pop弹出

a = [1,2,3,7]
b = [3,4,5]

def merge_sortedlist(a,b):
c = []
while a and b:
if a[0] >= b[0]:
c.append(b.pop(0))
else:
c.append(a.pop(0))
while a:
c.append(a.pop(0))
while b:
c.append(b.pop(0))
return c
print merge_sortedlist(a,b)

#第三种方法
def merge(a, b):
c = []
h = j = 0
while j < len(a) and h < len(b):
if a[j] < b[h]:
c.append(a[j])
j += 1
else:
c.append(b[h])
h += 1

if j == len(a):  
    for i in b\[h:\]:  
        c.append(i)  
else:  
    for i in a\[j:\]:  
        c.append(i)

return c

12.交叉链表求交点

其实思想可以按照从尾开始比较两个链表,如果相交,则从尾开始必然一致,只要从尾开始比较,直至不一致的地方即为交叉点,如图所示

另外一种比较正规的方法,构造链表类

class Node(object):
def __init__(self, value=None, next=None):
self.value = value
self.next = next

def get_list_length(head):
"""获取链表长度"""
length = 0
while head:
length += 1
head = head.next
return length

def get_intersect_node(list_a, list_b):
"""查找链表第一个交叉结点"""
length_a = get_list_length(list_a)
length_b = get_list_length(list_b)

cur1, cur2 = list\_a, list\_b  
if length\_a > length\_b:  
    for i in range(length\_a - length\_b):  
        cur1 = cur1.next  
else:  
    for i in range(length\_b - length\_a):  
        cur2 = cur2.next

flag = False  
while cur1 and cur2:  
    if cur1.value == cur2.value:  
        print(cur1.value)  
        flag = True  
        break  
    else:  
        cur1 = cur1.next  
        cur2 = cur2.next

if not flag:  
    print('链表没有交叉结点')

if __name__ == '__main__':
list_a = Node('a1', Node('a2', Node('c1', Node('c2', Node('c3'))))) # 构造不带头结点的链表:a1→a2→c1→c2→c3
list_b = Node('b1', Node('b2', Node('b3', Node('c1', Node('c2', Node('c3')))))) # 构造不带头结点的链表:b1→b2→b3→c1→c2→c3

get\_intersect\_node(list\_a, list\_b)

13.二分查找

#coding:utf-8
def binary_search(list, item):
low = 0
high = len(list) - 1
while low <= high: mid = (high - low) / 2 + low # 避免(high + low) / 2溢出 guess = list[mid] if guess > item:
high = mid - 1
elif guess < item:
low = mid + 1
else:
return mid
return None
mylist = [1,3,5,7,9]
print binary_search(mylist, 3)

14.快排

#coding:utf-8
def quicksort(list):
if len(list)<2: return list else: midpivot = list\[0\] lessbeforemidpivot = \[i for i in list\[1:\] if i<=midpivot\] biggerafterpivot = \[i for i in list\[1:\] if i > midpivot]
finallylist = quicksort(lessbeforemidpivot)+[midpivot]+quicksort(biggerafterpivot)
return finallylist

print(quicksort([2,4,6,7,1,2,5]))

15.找零问题

#coding:utf-8
#values是硬币的面值values = [ 25, 21, 10, 5, 1]
#valuesCounts 钱币对应的种类数
#money 找出来的总钱数
#coinsUsed 对应于目前钱币总数i所使用的硬币数目

def coinChange(values,valuesCounts,money,coinsUsed):
#遍历出从1到money所有的钱数可能
for cents in range(1,money+1):
minCoins = cents
#把所有的硬币面值遍历出来和钱数做对比
for kind in range(0,valuesCounts):
if (values[kind] <= cents):
temp = coinsUsed[cents - values[kind]] +1
if (temp < minCoins):
minCoins = temp
coinsUsed[cents] = minCoins
print ('面值:{0}的最少硬币使用数为:{1}'.format(cents, coinsUsed[cents]))

16.广度遍历和深度遍历二叉树

17.二叉树节点

class Node(object):
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right

tree = Node(1, Node(3, Node(7, Node(0)), Node(6)), Node(2, Node(5), Node(4)))

18.图的广度优先遍历

import Queue

def bfs(adj, start):
visited = set()
q = Queue.Queue()
q.put(start)
while not q.empty():
u = q.get()
print(u)
for v in adj.get(u, []):
if v not in visited:
  visited.add(v)
  q.put(v)

graph = {1: [4, 2], 2: [3, 4], 3: [4], 4: [5]}
bfs(graph, 1)

19.图的深度优先遍历

def dfs(adj, start):
visited = set()
stack = [[start, 0]]
while stack:
(v, next_child_idx) = stack[-1]
if (v not in adj) or (next_child_idx >= len(adj[v])):
stack.pop()
continue
next_child = adj[v][next_child_idx]
stack[-1][1] += 1
if next_child in visited:
continue
print(next_child)
visited.add(next_child)
stack.append([next_child, 0])

graph = {1: [4, 2], 2: [3, 4], 3: [4], 4: [5]}
dfs(graph, 1)
————————————————

上面的代码是dfs的非递归实现,其实递归的代码更简单,但是我觉得使用了函数的递归调用隐含了对栈的使用但是却没有明确出来,这样不太利于对dfs核心思想的理解,所以这里反而选择了更复杂的非递归实现。

整个程序借助了一个栈,由于python没有直接的实现栈,这里使用了list来模拟,入栈就是向列表中append一个元素,出栈就是取列表最后一个元素然后pop将最后一个元素删除

下面来分析实现过程,还是按之前的那句话“顺着起点往下走,直到无路可走就退回去找下一条路径,直到走完所有的结点”,整个程序都蕴含在这句话中:

首次是“顺着起点往下走”中的起点当然就是函数传进来的参数start,第三行中我们把起点放到了栈中,此时栈就是初始状态,其中就只有一个元素即起点。那么栈中元素表示的语义是:下一次将访问的结点,没错就这么简单,那么为什么我们一个结点和一个索引来表示呢?理由是这样的,由于我们使用邻接表来表示图,那么要表示一个结点表可以用<这个结点的父结点、这个结是父结点的第几个子结点>来决定,至于为什么要这么表示,就还是前面说的:由这们这里使用的图的存储方式-邻接表决定了,因为这样我们取第N个兄弟结点要容易了。因为邻接表中用list来表示一个结点的所有子结点,我们就用一个整数的索引值来保存下次要访问的子结点的list的下标,当这个下标超过子结点list的长度时意味着访问完所有子结点。

接着,“往下走”,看这句:next_child = adj[v][next_child_idx]就是我们在这个while循环中每次访问的都是一个子结点,访问完当前结点后stack.append([next_child, 0])将这个结点放到栈中,意思是下次就访问这个结点的子结点,这样就每次都是往下了。

“直到无路可走”,在程序中的体现就是 if (v not in adj) or (next_child_idx >= len(adj[v])):,栈顶元素表示即将要访问的结点的父结点及其是父结点的第N个子结点(有点绕),这里的意思是如果这个父结点都没有子结点了或者是我们想要访问第N个子结点但是父结点并没有这么多子结点,表示已经访问完了一个父结点的所有子结点了。

接着“就退回去找下一条路径”中的“退回去”,怎么退回去,很简单将栈顶元素弹出,新的栈顶元素就是它的父结点,那么就是退回去了,“去找下一条路径”就是弹出栈顶后下一次while中会沿着父结点继续探索,也就是去找下一条路径了。

最后“直到走完所有的结点“当然就是栈为空了,栈为空表示已经回退到起点,即所有结点已经访问完了,整个算法结束。

20.前中后序遍历

#coding:utf-8
#二叉树的遍历
#简单的二叉树节点类
class Node(object):
def __init__(self,value,left,right):
self.value = value
self.left = left
self.right = right

#中序遍历:遍历左子树,访问当前节点,遍历右子树

def mid_travelsal(root):
if root.left is not None:
mid_travelsal(root.left)
#访问当前节点
print(root.value)
if root.right is not None:
mid_travelsal(root.right)

#前序遍历:访问当前节点,遍历左子树,遍历右子树

def pre_travelsal(root):
print (root.value)
if root.left is not None:
pre_travelsal(root.left)
if root.right is not None:
pre_travelsal(root.right)

#后续遍历:遍历左子树,遍历右子树,访问当前节点

def post_trvelsal(root):
if root.left is not None:
post_trvelsal(root.left)
if root.right is not None:
post_trvelsal(root.right)
print (root.value)

21.求最大树深

def maxDepth(root):
if not root:
return 0
return max(maxDepth(root.left), maxDepth(root.right)) + 1

22.求两棵树是否相同

def isSameTree(p, q):
if p == None and q == None:
return True
elif p and q :
return p.val == q.val and isSameTree(p.left,q.left) and isSameTree(p.right,q.right)
else :
return False

23.前序中序求后序

def rebuild(pre, center):
if not pre:
return
cur = Node(pre[0])
index = center.index(pre[0])
cur.left = rebuild(pre[1:index + 1], center[:index])
cur.right = rebuild(pre[index + 1:], center[index + 1:])
return cur

def deep(root):
if not root:
return
deep(root.left)
deep(root.right)
print root.data

24.单链表逆置

class Node(object):
def __init__(self, data=None, next=None):
self.data = data
self.next = next

link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9)))))))))

def rev(link):
pre = link
cur = link.next
pre.next = None
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre

root = rev(link)
while root:
print root.data
root = root.next

25.两个字符串是否是变位词

问题描述:写出一个函数 anagram(s, t) 判断两个字符串是否可以通过改变字母的顺序变成一样的字符串。

样例

给出 s = "abcd",t="dcab",返回 true.
给出 s = "ab", t = "ab", 返回 true.
给出 s = "ab", t = "ac", 返回 false

class Anagram:
"""
@:param s1: The first string
@:param s2: The second string
@:return true or false
"""
def Solution1(s1,s2):
alist = list(s2)

    pos1 = 0  
    stillOK = True

    while pos1 < len(s1) and stillOK:  
        pos2 = 0  
        found = False  
        while pos2 < len(alist) and not found:  
            if s1\[pos1\] == alist\[pos2\]:  
                found = True  
            else:  
                pos2 = pos2 + 1

        if found:  
            alist\[pos2\] = None  
        else:  
            stillOK = False

        pos1 = pos1 + 1

    return stillOK

print(Solution1('abcd','dcba'))

def Solution2(s1,s2):  
    alist1 = list(s1)  
    alist2 = list(s2)

    alist1.sort()  
    alist2.sort()

    pos = 0  
    matches = True

    while pos < len(s1) and matches:  
        if alist1\[pos\] == alist2\[pos\]:  
            pos = pos + 1  
        else:  
            matches = False

    return matches

print(Solution2('abcde','edcbg'))

def Solution3(s1,s2):  
    c1 = \[0\]\*26  
    c2 = \[0\]\*26

    for i in range(len(s1)):  
        pos = ord(s1\[i\])-ord('a')  
        c1\[pos\] = c1\[pos\] + 1

    for i in range(len(s2)):  
        pos = ord(s2\[i\])-ord('a')  
        c2\[pos\] = c2\[pos\] + 1

    j = 0  
    stillOK = True  
    while j<26 and stillOK:  
        if c1\[j\] == c2\[j\]:  
            j = j + 1  
        else:  
            stillOK = False

    return stillOK

print(Solution3('apple','pleap'))

class Solution:
    def anagram(self, s, t):
        m = list(s)
        n = list(t)
        m.sort()
        n.sort()
        if m == n:
            return True
        else:
            return False

26.现有字典 d= {'a':24,'g':52,'i':12,'k':33}请按value值进行排序?

sorted(d.items(),key=lambda x:x[1])

27.请反转字符串 "aStr"?

print("aStr"[::-1])

28.将字符串 "k:1 |k1:2|k2:3|k3:4",处理成字典 {k:1,k1:2,…}

str1 = "k:1|k1:2|k2:3|k3:4"
def str2dict(str1):
dict1 = {}
for iterms in str1.split('|'):
key,value = iterms.split(':')
dict1[key] = value
return dict1
#字典推导式
d = {k:int(v) for t in str1.split("|") for k, v in (t.split(":"), )}

29.请按alist中元素的age由大到小排序

alist = [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}]
def sort_by_age(list1):
return sorted(alist,key=lambda x:x['age'],reverse=True)

30.下面代码的输出结果将是什么?

list = ['a','b','c','d','e']
print(list[10:])

代码将输出[],不会产生IndexError错误,就像所期望的那样,尝试用超出成员的个数的index来获取某个列表的成员。例如,尝试获取list[10]和之后的成员,会导致IndexError。然而,尝试获取列表的切片,开始的index超过了成员个数不会产生IndexError,而是仅仅返回一个空列表。这成为特别让人恶心的疑难杂症,因为运行的时候没有错误产生,导致Bug很难被追踪到。

33.写一个列表生成式,产生一个公差为11的等差数列

print([x*11 for x in range(10)])

34.给定两个列表,怎么找出他们相同的元素和不同的元素?

list1 = [1,2,3]
list2 = [3,4,5]
set1 = set(list1)
set2 = set(list2)
print(set1 & set2)
print(set1 ^ set2)

36.给定两个list A,B ,请用找出A,B中相同与不同的元素

A,B 中相同元素: print(set(A)&set(B))
A,B 中不同元素: print(set(A)^set(B))

37.反转一个整数,例如-123 --> -321

class Solution(object):
def reverse(self,x):
if -10<x<10:
return x
str_x = str(x)
if str_x[0] !="-":
str_x = str_x[::-1]
x = int(str_x)
else:
str_x = str_x[1:][::-1]
x = int(str_x)
x = -x
return x if -2147483648<x<2147483647 else 0
if __name__ == '__main__':
s = Solution()
reverse_int = s.reverse(-120)
print(reverse_int)

38.设计实现遍历目录与子目录,抓取.pyc文件

import os

def pick(obj):
if obj.endswith(".pyc"):
print(obj)

def scan_path(ph):
file_list = os.listdir(ph)
for obj in file_list:
if os.path.isfile(obj):
pick(obj)
elif os.path.isdir(obj):
scan_path(obj)

if __name__=='__main__':
path = input('输入目录')
scan_path(path)

39.一行代码实现1-100之和

count = sum(range(0,101))
print(count)

40.Python-遍历列表时删除元素的正确做法

a=[1,2,3,4,5,6,7,8]
b = filter(lambda x: x>5,a)
print(list(b))

41.字符串的操作题目

42.求出列表所有奇数并构造新列表

a = [1,2,3,4,5,6,7,8,9,10]
res = [ i for i in a if i%2==1]
print(res)

43.用一行python代码写出1+2+3+10248

from functools import reduce
#1.使用sum内置求和函数
num = sum([1,2,3,10248])
print(num)
#2.reduce 函数
num1 = reduce(lambda x,y :x+y,[1,2,3,10248])
print(num1)

44.Python中变量的作用域?(变量查找顺序)

函数作用域的LEGB顺序

1.什么是LEGB?

L: local 函数内部作用域

E: enclosing 函数内部与内嵌函数之间

G: global 全局作用域

B: build-in 内置作用

python在函数里面的查找分为4种,称之为LEGB,也正是按照这是顺序来查找的

45.字符串 "123" 转换成 123,不使用内置api,例如 int()

def atoi(s):
num = 0
for v in s:
for j in range(10):
if v == str(j):
num = num * 10 + j
return num

46.给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。

你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。示例:给定nums = [2,7,11,15],target=9 因为 nums[0]+nums[1] = 2+7 =9,所以返回[0,1]

class Solution:
def twoSum(self,nums,target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
d = {}
size = 0
while size < len(nums):
if target-nums[size] in d:
if d[target-nums[size]] <size:
return [d[target-nums[size]],size]
else:
d[nums[size]] = size
size = size +1
solution = Solution()
list = [2,7,11,15]
target = 9
nums = solution.twoSum(list,target)
print(nums)

def solution(nums,target):
#新建立一个空字典用来保存数值及其在列表中对应的索引
dict1 = {}
#遍历一遍列表对应的时间复杂度为O(n)
for i in range(0, len(nums)):
#相减得到另一个数值
num = target - nums[i]
#如果另一个数值不在字典中,则将第一个数值及其的索引报错在字典中
#因为在字典中查找的时间复杂度为O(1),因此总时间复杂度为O(n)
if num not in dict1:
dict1[nums[i]] = i
#如果在字典中则返回
else:
return [dict1[num], i]

48.统计一个文本中单词频次最高的10个单词?

import re

方法一

def test(filepath):

distone = {}

with open(filepath) as f:  
    for line in f:  
        line = re.sub("\\W+", " ", line)  
        lineone = line.split()  
        for keyone in lineone:  
            if not distone.get(keyone):  
                distone\[keyone\] = 1  
            else:  
                distone\[keyone\] += 1  
num\_ten = sorted(distone.items(), key=lambda x:x\[1\], reverse=True)\[:10\]  
num\_ten =\[x\[0\] for x in num\_ten\]  
return num\_ten

方法二

使用 built-in 的 Counter 里面的 most_common

import re
from collections import Counter

def test2(filepath):
with open(filepath) as f:
return list(map(lambda c: c[0], Counter(re.sub("\W+", " ", f.read()).split()).most_common(10)))

49.请写出一个函数满足以下条件

该函数的输入是一个仅包含数字的list,输出一个新的list,其中每一个元素要满足以下条件:

1、该元素是偶数

2、该元素在原list中是在偶数的位置(index是偶数)

def num_list(num):
return [i for i in num if i %2 ==0 and num.index(i)%2==0]

num = [0,1,2,3,4,5,6,7,8,9,10]
result = num_list(num)
print(result)

50.使用单一的列表生成式来产生一个新的列表

list_data = [1,2,5,8,10,3,18,6,20]
res = [x for x in list_data[::2] if x %2 ==0]
print(res)

51.输入某年某月某日,判断这一天是这一年的第几天?

import datetime

y = int(input("请输入4位数字的年份:"))
m = int(input("请输入月份:"))
d = int(input("请输入是哪一天"))

targetDay = datetime.date(y,m,d)
dayCount = targetDay - datetime.date(targetDay.year -1,12,31)
print("%s是 %s年的第%s天。"%(targetDay,y,dayCount.days))

52.两个有序列表,l1,l2,对这两个列表进行合并不可使用extend

def loop_merge_sort(l1,l2):
tmp = []
while len(l1)>0 and len(l2)>0:
if l1[0] 0:
tmp.append(l1[0])
del l1[0]
while len(l2)>0:
tmp.append(l2[0])
del l2[0]
return tmp

53.给定一个任意长度数组,实现一个函数
让所有奇数都在偶数前面,而且奇数升序排列,偶数降序排序,如字符串'1982376455',变成'1355798642'

# 方法一
def func1(l):
if isinstance(l, str):
l = [int(i) for i in l]
l.sort(reverse=True)
for i in range(len(l)):
if l[i] % 2 > 0:
l.insert(0, l.pop(i))
print(''.join(str(e) for e in l))

54.写一个函数找出一个整数数组中,第二大的数

def find_second_large_num(num_list):
"""
找出数组第2大的数字
"""
# 方法一
# 直接排序,输出倒数第二个数即可
tmp_list = sorted(num_list)
print("方法一\nSecond_large_num is :", tmp_list[-2])

# 方法二  
# 设置两个标志位一个存储最大数一个存储次大数  
# two 存储次大值,one 存储最大值,遍历一次数组即可,先判断是否大于 one,若大于将 one 的值给 two,将 num\_list\[i\] 的值给 one,否则比较是否大于two,若大于直接将 num\_list\[i\] 的值给two,否则pass  
one = num\_list\[0\]  
two = num\_list\[0\]  
for i in range(1, len(num\_list)):  
    if num\_list\[i\] > one:  
        two = one  
        one = num\_list\[i\]  
    elif num\_list\[i\] > two:  
        two = num\_list\[i\]  
print("方法二\\nSecond\_large\_num is :", two)

# 方法三  
# 用 reduce 与逻辑符号 (and, or)  
# 基本思路与方法二一样,但是不需要用 if 进行判断。  
from functools import reduce  
num = reduce(lambda ot, x: ot\[1\] < x and (ot\[1\], x) or ot\[0\] < x and (x, ot\[1\]) or ot, num\_list, (0, 0))\[0\]  
print("方法三\\nSecond\_large\_num is :", num)

if __name__ == '__main___':
num_list = [34, 11, 23, 56, 78, 0, 9, 12, 3, 7, 5]
find_second_large_num(num_list)

55.统计一段字符串中字符出现的次数

# 方法一
def count_str(str_data):
"""定义一个字符出现次数的函数"""
dict_str = {}
for i in str_data:
dict_str[i] = dict_str.get(i, 0) + 1
return dict_str
dict_str = count_str("AAABBCCAC")
str_count_data = ""
for k, v in dict_str.items():
str_count_data += k + str(v)
print(str_count_data)

方法二

from collections import Counter

print("".join(map(lambda x: x[0] + str(x[1]), Counter("AAABBCCAC").most_common())))