写点什么

测试面试 | Python 算法与数据结构面试题系列二(附答案)

  • 2022 年 8 月 30 日
    北京
  • 本文字数:5360 字

    阅读完需:约 18 分钟

1. 排序实现

有一组“+”和“-”符号,要求将“+”排到左边,“-”排到右边,写出具体的实现方法。

答:

如果让+等于 0,-等于 1 不就是排序了么

from collections import dequefrom timeit import Timer
s = "++++++----+++----"
# 方法一def func1(): new_s = s.replace("+", "0").replace("-", "1") result = "".join(sorted(new_s)).replace("0", "+").replace("1", "-") return result
# 方法二def func2(): q = deque() left = q.appendleft right = q.append for i in s: if i == "+": left("+") elif i == "-": right("-")
# 方法三def func3(): data = list(s) start_index = 0 end_index = 0 count = len(s) while start_index + end_index < count: if data[start_index] == '-': data[start_index], data[count - end_index - 1] = data[count - end_index - 1], data[start_index] end_index += 1 else : start_index += 1 return "".join(data)
if __name__ == '__main__': timer1 = Timer("func1()", "from __main__ import func1") print("func1", timer1.timeit(1000000)) timer2 = Timer("func2()", "from __main__ import func2") print("func2", timer2.timeit(1000000)) timer3 = Timer("func3()", "from __main__ import func3") print("func3", timer3.timeit(1000000))
# 1000000 测试结果# func1 1.39003764# func2 1.593012875# func3 3.3487415590000005# func1 的方式最优,其次是 func2
复制代码

2. 单链表反转

答:

单链表反转

class Node:    def __init__(self, val=None):        self.val = val        self.next = None
class SingleLinkList: def __init__(self, head=None): """链表的头部""" self._head = head
def add(self, val:int): """ 给链表添加元素 :param val: 传过来的数字 :return: """ # 创建一个节点 node = Node(val) if self._head is None: self._head = node else : cur = self._head while cur.next is not None: cur = cur.next # 移动游标 cur.next = node # 如果 next 后面没了证明以及到最后一个节点了
def traversal(self): if self._head is None: return else : cur = self._head while cur is not None: print(cur.val) cur = cur.next
def size(self): """ 获取链表的大小 :return: """ count = 0 if self._head is None: return count else : cur = self._head while cur is not None: count += 1 cur = cur.next return count
def reverse(self): """ 单链表反转 思路: 让 cur.next 先断开即指向 none,指向设定 pre 游标指向断开的元素,然后 cur.next 指向断开的元素,再把开始 self._head 再最后一个元素的时候. :return: """ if self._head is None or self.size() == 1: return else : pre = None cur = self._head while cur is not None: post = cur.next cur.next = pre pre = cur cur = post self._head = pre # 逆向后的头节点
if __name__ == '__main__': single_link = SingleLinkList() single_link.add(3) single_link.add(5) single_link.add(6) single_link.add(7) single_link.add(8) print("对链表进行遍历") single_link.traversal() print(f"size:{single_link.size()}") print("对链表进行逆向操作之后") single_link.reverse() single_link.traversal()
复制代码

3. 交叉链表求交点

答:

# Definition for singly-linked list.class ListNode:    def __init__(self, x):        self.val = x        self.next = None
class Solution: def getIntersectionNode(self, headA, headB): """ :tye head1, head1: ListNode :rtye: ListNode """ if headA is not None and headB is not None: cur1, cur2 = headA, headB
while cur1 != cur2: cur1 = cur1.next if cur1 is not None else headA cur2 = cur2.next if cur2 is not None else headB
return cur1
复制代码

cur1、cur2,2 个指针的初始位置是链表 headA、headB 头结点,cur1、cur2 两个指针一直往后遍历。直到 cur1 指针走到链表的末尾,然后 cur1 指向 headB;直到 cur2 指针走到链表的末尾,然后 cur2 指向 headA;然后再继续遍历。

每次 cur1、cur2 指向 None,则将 cur1、cur2 分别指向 headB、headA。循环的次数越多,cur1、cur2 的距离越接近,直到 cur1 等于 cur2。则是两个链表的相交点。

4. 用队列实现栈 ww

**答: **

下面代码分别使用 1 个队列和 2 个队列实现了栈。

from queue import Queue# 使用 2 个队列实现class MyStack:    def __init__(self):        """        Initialize your data structure here.        """        # q1 作为进栈出栈,q2 作为中转站        self.q1 = Queue()        self.q2 = Queue()
def push(self, x): """ Push element x onto stack. :type x: int :rtype: void """ self.q1.put(x)
def pop(self):
""" Removes the element on top of the stack and returns that element. :rtype: int """
while self.q1.qsize() > 1: self.q2.put(self.q1.get()) # 将 q1 中除尾元素外的所有元素转到 q2 中 if self.q1.qsize() == 1: res = self.q1.get() # 弹出 q1 的最后一个元素 self.q1, self.q2 = self.q2, self.q1 # 交换 q1,q2 return res
def top(self):
""" Get the top element. :rtype: int """ while self.q1.qsize() > 1: self.q2.put(self.q1.get()) # 将 q1 中除尾元素外的所有元素转到 q2 中 if self.q1.qsize() == 1: res = self.q1.get() # 弹出 q1 的最后一个元素 self.q2.put(res) # 与 pop 唯一不同的是需要将 q1 最后一个元素保存到 q2 中 self.q1, self.q2 = self.q2, self.q1 # 交换 q1,q2 return res
def empty(self): """ Returns whether the stack is empty. :rtype: bool """ return not bool(self.q1.qsize() + self.q2.qsize()) # 为空返回 True,不为空返回 False # 使用 1 个队列实现 class MyStack2(object): def __init__(self): """ Initialize your data structure here. """ self.sq1 = Queue()
def push(self, x): """ Push element x onto stack. :type x: int :rtype: void """ self.sq1.put(x)
def pop(self): """ Removes the element on top of the stack and returns that element. :rtype: int """ count = self.sq1.qsize() if count == 0: return False while count > 1: x = self.sq1.get() self.sq1.put(x) count -= 1 return self.sq1.get()
def top(self): """ Get the top element. :rtype: int """ count = self.sq1.qsize() if count == 0: return False while count: x = self.sq1.get() self.sq1.put(x) count -= 1 return x
def empty(self): """ Returns whether the stack is empty. :rtype: bool """ return self.sq1.empty()
if __name__ == '__main__': obj = MyStack2() obj.push(1) obj.push(3) obj.push(4) print(obj.pop()) print(obj.pop()) print(obj.pop()) print(obj.empty())
复制代码

5. 找出数据流的中位数

答:

对于一个升序排序的数组,中位数为左半部分的最大值,右半部分的最小值,而左右两部分可以是无需的,只要保证左半部分的数均小于右半部分即可。因此,左右两半部分分别可用最大堆、最小堆实现。

如果有奇数个数,则中位数放在左半部分;如果有偶数个数,则取左半部分的最大值、右边部分的最小值之平均值。分两种情况讨论:

当目前有偶数个数字时,数字先插入最小堆,然后选择最小堆的最小值插入最大堆(第一个数字插入左半部分的最小堆)。当目前有奇数个数字时,数字先插入最大堆,然后选择最大堆的最大值插入最小堆。

  • 最大堆:根结点的键值是所有堆结点键值中最大者,且每个结点的值都比其孩子的值大。

  • 最小堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的值小。

# -*- coding:utf-8 -*-from heapq import *
class Solution: def __init__(self): self.maxheap = [] self.minheap = []
def Insert(self, num): if (len(self.maxheap) + len(self.minheap)) & 0x1: # 总数为奇数插入最大堆 if len(self.minheap) > 0: if num > self.minheap[0]: # 大于最小堆里的元素 heappush(self.minheap, num) # 新数据插入最小堆 heappush(self.maxheap, -self.minheap[0]) # 最小堆中的最小插入最大堆 heappop(self.minheap) else : heappush(self.maxheap, -num) else : heappush(self.maxheap, -num) else : # 总数为偶数 插入最小堆 if len(self.maxheap) > 0: # 小于最大堆里的元素 if num < -self.maxheap[0]: heappush(self.maxheap, -num) # 新数据插入最大堆 heappush(self.minheap, -self.maxheap[0]) # 最大堆中的最大元素插入最小堆 heappop(self.maxheap) else : heappush(self.minheap, num) else : heappush(self.minheap, num)
def GetMedian(self, n=None): if (len(self.maxheap) + len(self.minheap)) & 0x1: mid = self.minheap[0] else : mid = (self.minheap[0] - self.maxheap[0]) / 2.0 return mid
if __name__ == '__main__': s = Solution() s.Insert(1) s.Insert(2) s.Insert(3) s.Insert(4) print(s.GetMedian())
复制代码

6. 二叉搜索树中第 K 小的元素

答:

二叉搜索树(BinarySearchTree),又名二叉排序树(BinarySortTree)。二叉搜索树是具有有以下性质的二叉树:

  • 若左子树不为空,则左子树上所有节点的值均小于或等于它的根节点的值。

  • 若右子树不为空,则右子树上所有节点的值均大于或等于它的根节点的值。

左、右子树也分别为二叉搜索树。二叉搜索树按照中序遍历的顺序打印出来正好就是排序好的顺序。所以对其遍历一个节点就进行计数,计数达到 k 的时候就结束。

class TreeNode:    def __init__(self, x):        self.val = x        self.left = None        self.right = None
class Solution: count = 0 nodeVal = 0
def kthSmallest(self, root, k): """ :type root: TreeNode :type k: int :rtype: int """ self.dfs(root, k) return self.nodeVal
def dfs(self, node, k):
if node != None: self.dfs(node.left, k) self.count = self.count + 1 if self.count == k: self.nodeVal = node.val # 将该节点的左右子树置为 None,来结束递归,减少时间复杂度 node.left = None node.right = None self.dfs(node.right, k)
复制代码

更多 Python 编程常见面试题,我们后续继续分享,敬请关注。


免费领取:性能测试+接口测试+自动化测试+测试开发+测试用例+简历模板+测试文档

http://qrcode.testing-studio.com/f?from=infoQ&url=https://ceshiren.com/t/topic/16565

用户头像

社区:ceshiren.com 微信:ceshiren2021 2019.10.23 加入

微信公众号:霍格沃兹测试开发 提供性能测试、自动化测试、测试开发等资料,实时更新一线互联网大厂测试岗位内推需求,共享测试行业动态及资讯,更可零距离接触众多业内大佬。

评论

发布
暂无评论
测试面试 | Python 算法与数据结构面试题系列二(附答案)_霍格沃兹测试开发学社_InfoQ写作社区