zoukankan      html  css  js  c++  java
  • 【面试-python】

    1.使用Python实现删除list的重复元素

    a = [3,4,5,2,3,4]
    b = {}
    b = b.fromkeys(a)
    c = c.list(b.keys())
    print(c)

    2.python 如何进行内存管理的?

    从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制
    
    一、对象的引用计数机制
    Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
    
    引用计数增加的情况:
    1,一个对象分配一个新名称
    2,将其放入一个容器中(如列表、元组或字典)
    
    引用计数减少的情况:
    1,使用del语句对对象别名显示的销毁
    2,引用超出作用域或被重新赋值
    sys.getrefcount( )函数可以获得对象的当前引用计数
    多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。
    
    二、垃圾回收
    1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
    2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。
    
    三、内存池机制
    Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
    1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
    2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。
    3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

    3.Python里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)

    赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。
    
    浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变){1,完全切片方法;2,工厂函数,如list();3,copy模块的copy()函数}
    
    深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变){copy模块的deep.deepcopy()函数}

    4.Python手写实现冒泡排序

    冒泡排序的原理不难,假定要将被排序的数组R[1..n]从大到小垂直排列,每个数字R可以看作是重量为R.key的气泡。
    
    根据轻气泡在上、重气泡在上的原则,从下往上扫描数组R:凡扫描到违反本原则的轻气泡,则使其向上"飘浮"。如此反复进行,直到最后任何两个气泡都是轻者在上、重者在下为止。
    然后将所有气泡逆序,就实现了数组从小到大的排序。
    
    步骤:
    1 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
    2 对第0个到第n-1个数据做同样的工作。这时,最大的数就到了数组最后的位置上。
    3 针对所有的元素重复以上的步骤,除了最后一个。
    4 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
    
    Python实现
    
    def bubble_sort(arry):
        #获得数组的长度
        n = len(arry)                   
        for i in range(n):
            for j in range(1,n-i):
                #如果前者比后者大
                if  arry[j-1] > arry[j] :  
                    #则交换两者     
                    arry[j-1],arry[j] = arry[j],arry[j-1]      
        return arry

    5. Python手写实现选择排序

    选择排序(Selection sort)是一种简单直观的排序算法。
    
    它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列第二个位置。以此类推,直到所有元素均排序完毕。
    
    Python实现
    
    def select_sort(ary):
        n = len(ary)
        for i in range(0,n):
            #最小元素下标标记
            min = i                             
            for j in range(i+1,n):
                if ary[j] < ary[min] :
                    #找到最小值的下标
                    min = j
            #交换两者                     
            ary[min],ary[i] = ary[i],ary[min]   
        return ary

    6.请用Python手写实现插入排序

    插入排序(Insertion Sort)的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
    
    算法执行步骤:
    1 从第一个元素开始,该元素可以认为已经被排序
    2 取出下一个元素,在已经排序的元素序列中从后向前扫描
    3 如果被扫描的元素(已排序)大于新元素,则将被扫描元素后移一位
    4 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
    5 将新元素插入到该位置后
    6 重复步骤2~5
    
    
    
    Python实现
    
    def insert_sort(ary):
        n = len(ary)
        for i in range(1,n):
            if ary[i] < ary[i-1]:
                temp = ary[i]
    
                #待插入的下标
                index = i           
                #从i-1 循环到 0 (包括0)
                for j in range(i-1,-1,-1):  
                    if ary[j] > temp :
                        ary[j+1] = ary[j]
                        #记录待插入下标
                        index = j   
                    else :
                        break
                ary[index] = temp
        return ary

    7.Python手写实现快速排序

    1 从数列中挑出一个元素,称为 “基准”(pivot),
    2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
    3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
    
    换言之
    快速排序时基于分治模式处理的,
    对一个典型子数组A[p...r]排序的分治过程为三个步骤:
    1.分解:
    A[p..r]被划分为俩个(可能空)的子数组A[p ..q-1]和A[q+1 ..r],使得
    A[p ..q-1] 

    8.请用Python手写实现堆排序

    堆排序在 top K 问题中使用比较频繁。堆排序是采用二叉堆的数据结构来实现的,虽然实质上还是一维数组。二叉堆是一个近似完全二叉树 。
    
    二叉堆具有以下性质:
    
    父节点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
    每个节点的左右子树都是一个二叉堆(都是最大堆或最小堆)。
    
    步骤:
    1 构造最大堆(Build_Max_Heap):若数组下标范围为0~n,考虑到单独一个元素是大根堆,则从下标n/2开始的元素均为大根堆。于是只要从n/2-1开始,向前依次构造大根堆,这样就能保证,构造到某个节点时,它的左右子树都已经是大根堆。
    
    2 堆排序(HeapSort):由于堆是用数组模拟的。得到一个大根堆后,数组内部并不是有序的。因此需要将堆化数组有序化。思想是移除根节点,并做最大堆调整的递归运算。第一次将heap[0]与heap[n-1]交换,再对heap[0...n-2]做最大堆调整。第二次将heap[0]与heap[n-2]交换,再对heap[0...n-3]做最大堆调整。重复该操作直至heap[0]和heap[1]交换。由于每次都是将最大的数并入到后面的有序区间,故操作完后整个数组就是有序的了。
    
    3 最大堆调整(Max_Heapify):该方法是提供给上述两个过程调用的。目的是将堆的末端子节点作调整,使得子节点永远小于父节点。
    
    
    
    Python实现
    def heap_sort(ary) :
        n = len(ary)
        #最后一个非叶子节点
        first = int(n/2-1)       
        #构造大根堆
        for start in range(first,-1,-1) :     
            max_heapify(ary,start,n-1)
    
        #堆排,将大根堆转换成有序数组
        for end in range(n-1,0,-1):           
            ary[end],ary[0] = ary[0],ary[end]
            max_heapify(ary,0,end-1)
        return ary
    
    #最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点
    #start为当前需要调整最大堆的位置,end为调整边界
    def max_heapify(ary,start,end):
        root = start
        while True :
            #调整节点的子节点
            child = root*2 +1               
            if child > end : break
            if child+1 

    9,请用Python手写实现归并排序

    归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。
    
    先考虑合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
    
    再考虑递归分解,基本思路是将数组分解成left和right,如果这两个数组内部数据是有序的,那么就可以用上面合并数组的方法将这两个数组合并排序。如何让这两个数组内部是有序的?可以再二分,直至分解出的小组只含有一个元素时为止,此时认为该小组内部已有序。然后合并排序相邻二个小组即可。

    10.无序数组第k 大的元素

    思路:快排中partition 思想:
    对于某个索引j,nums[j] 经过partition 操作:
    nums[left] 到nums[j - 1] 中的所有元素都不大于nums[j];
    nums[j + 1] 到nums[right] 中的所有元素都不小于nums[j]
    即nums[j]元素的位置是排序好了的,我们判断索引j 是否满足条件,若满足则直接返回结果,若
    不满足我只需要遍历左序列或者右序列,直至满足要求;无需对整个序列进行排序,所以减少了计算
    量;
    1. class Solution:
    2. def findKthLargest(self, nums: List[int], k: int) -> int:
    3. # 快排中分治思想
    4. n = len(nums)
    5. left, right, target = 0, n-1, n - k
    6. while True:
    7. pivote = self.getPivote(nums, left, right)
    8. if pivote == target: return nums[target]
    9. # 只需遍历pivote 左边或者右边减少计算量
    10. elif pivote < target: left = pivote + 1
    11. elif pivote > target: right = pivote - 1
    12.
    13. # 分治思想pivote 左边都是不大于pivote 的数,右边是不小于pivote 的数
    14. def getPivote(self, nums, left, right):
    15. pivote = random.randint(left, right)
    16. nums[left], nums[pivote] = nums[pivote], nums[left]
    17. pivote = nums[left]
    18. # 双指针法
    19. while left < right:
    20. while nums[right] >= pivote and left < right: right -= 1
    21. nums[left] = nums[right]
    22. while nums[left] <= pivote and left < right: left += 1
    23. nums[right] = nums[left]
    24. nums[left] = pivote
    25. return left

  • 相关阅读:
    Python之操作MySQL数据库
    Python之进程与线程
    Python之socket网络编程
    网络基础之网络协议
    Python之log的处理方式
    11 python 操作mysql数据库
    10 线程 协程 socketserver 基于udp的socketserver
    9 异常处理 操作系统 进程线程 队列+生产消费者模型 进程同步 回调函数
    6 常用模块 (time,random,os,sys,shutil, json&pickle, shelve,xml,configparser,hashlib,suprocess,logging)
    ubuntu16上安装安装Docker图形化管理界面-Shipyard中文版
  • 原文地址:https://www.cnblogs.com/pergrand/p/15005731.html
Copyright © 2011-2022 走看看