1. 程式人生 > 其它 >【面試-python】

【面試-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