【面試-python】
阿新 • • 發佈:2021-07-13
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