zoukankan      html  css  js  c++  java
  • 测试面试 | Python 算法与数据结构面试题系列二(附答案)

    在这里插入图片描述

    ⬆️ 关注 @霍格沃兹测试学院 公众号,回复「面试」,领取 BAT 大厂测试面试真题专辑。

    1. 排序实现
      有一组“+”和“-”符号,要求将“+”排到左边,“-”排到右边,写出具体的实现方法。
      答:
      如果让+等于 0,-等于 1 不就是排序了么。
    from collections import deque
    from 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
    
    1. 单链表反转
      答:
      单链表反转
    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()
    
    1. 交叉链表求交点
      答:
    # 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())
    
    1. 找出数据流的中位数
      答:
      对于一个升序排序的数组,中位数为左半部分的最大值,右半部分的最小值,而左右两部分可以是无需的,只要保证左半部分的数均小于右半部分即可。因此,左右两半部分分别可用最大堆、最小堆实现。
      如果有奇数个数,则中位数放在左半部分;如果有偶数个数,则取左半部分的最大值、右边部分的最小值之平均值。分两种情况讨论:
      当目前有偶数个数字时,数字先插入最小堆,然后选择最小堆的最小值插入最大堆(第一个数字插入左半部分的最小堆)。当目前有奇数个数字时,数字先插入最大堆,然后选择最大堆的最大值插入最小堆。
      最大堆:根结点的键值是所有堆结点键值中最大者,且每个结点的值都比其孩子的值大。
      最小堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的值小。
    # -*- 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())
    
    1. 二叉搜索树中第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 编程常见面试题,我们后续继续分享,敬请关注。

    更多技术文章分享及测试资料点此获取

    在这里插入图片描述

  • 相关阅读:
    java注解说明
    paypal
    eclispe查看jdk源码后特别卡顿导致未响应解决
    ubuntu+tomcat,多环境、自动化部署脚本,git+maven+tomcat+ubuntu
    ubuntu+let's encrypt生成永久免费https证书 ubuntu+tomcat+nginx+let's encrypt
    MySQL创建数据库与创建用户以及授权
    linux查找并杀死进程shell
    redmine安装笔记
    C#动态获取本机可用串口的两种方式
    C# 控件缩写规范
  • 原文地址:https://www.cnblogs.com/hogwarts/p/14177243.html
Copyright © 2011-2022 走看看