面試題: 歸併算法 兩個有序序列進行歸併 l1 = [1, 2, 5, 6, 8,10] l2 = [3, 4, 7,9,12] l3 = [] i = 0 j = 0 while i < len(l1) and j < len(l2): if l1[i] < l2[j]: l3.append(l1[i]) i += 1 else: l3.append(l2[j]) j = j + 1 while i < len(l1): l3.append(l1[i]) i += 1 while i < len(l2): l3.append(l2[i]) i += 1 print(l3) 求階乘後結果的末尾0的個數 n= 5 rus = 1 while n>0: rus = rus*n n-=1 s = str(rus) count =0 s= '120000000' for i in range(len(s)-1,-1,-1): if s[i]=='0': count +=1 else: break print(count) 字典排序: alist =[{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}] alist = sorted(alist,key=lambda dic:dic['age']) print(alist) 斐波那契數列 a, b, c = 1, 2, 3 n = 400000 i = 0 while a < n: print(a) i += 1 a, b, c = b, c, b + c print(i) def fib(n): li = [1,1] for i in range(2,n+1): li.append(li[-1]+li[-2]) return li[-1] def fib(n): if n ==0 or n == 1: return 1 a = 1 b = 1 c = 1 for i in range(2,n+1): a = b b = c c = a + b return c # 青蛙跳臺階問題 def func(n): if n == 0: return 0 if n == 1: return 1 if n == 2: return 2 return func(n - 1) + func(n - 2) print(func(4)) 遞歸 漢諾塔問題 def hanoi(n,A,B,C): if n>0: hanoi(n-1,A,C,B) print('%s -> %s' % (A,C)) hanoi(n-1,B,A,C) hanoi(2,'A','B','C') 二分查找 def bin_search(li, val): '''使用low和high標註索引,mid爲中間索引,這裏的索引表明指針,每次以中間值比較大小,比較完後改變索引''' low = 0 high = len(li) - 1 while low <= high: mid = (high - low) // 2 if li[mid] > val: high = mid - 1 elif li[mid] < val: low = mid + 1 else: return mid return -1 使用and代替if語句 def func(): print('aaa') x = -3 x > 0 and func() # 等價於 if x > 0: func() # 因此可使用and代替if語句() # a and b <==> a if a == 0 else b # a or b <==> b if a == 0 else a [外排序,對大內存有效](https://www.cnblogs.com/codeMedita/p/7425291.html)
簡單的說就是先分段,將每段排好後,而後使用歸併排序,對於兩段進行歸併排序時,能夠一點點讀數據歸併,而後數據一點點寫入磁盤
如 1 2 3 5 6 12 18 20 24 和 4 5 7 20 25 30 21 25 26 進行歸併時,能夠先歸併前5個結果是 1 2 3 4 5 5 6 7 12 18 而後將歸併後結果寫入磁盤 十種排序算法 # 推薦:https://blog.csdn.net/yangnianjinxin/article/details/77918882 選擇排序、快速排序、希爾排序、堆排序不是穩定的排序算法,而冒泡排序、插入排序、歸併排序和基數排序是穩定的排序算法 low逼三人組 冒泡(穩定 o(n2)) # 走n趟,沒趟交換比較選出最大的 def bubble_sort(li): for i in range(len(li) - 1): exchange = False # 沒有交換表示已經排好序了,就不用再繼續執行了 for j in range(len(li) - 1 - i): if li[j] > li[j + 1]: li[j], li[j + 1] = li[j + 1], li[j] exchange = True if not exchange: return 選擇排序(不穩定) # 一趟遍歷選擇記錄中最小的數,放到第一個位置 # 再一趟遍歷記錄剩餘列表中最小的數,繼續放置 def select_sort(li): for i in range(len(li) - 1): min_pos = i for j in range(i + 1, len(li)): if li[j] < li[min_pos]: min_pos = j li[min_pos], li[j] = li[j], li[min_pos] 插入排序 # 列表分爲有序區和無序區兩個部分,最初有序區只有一個元素 # 每次從無序區選擇一個元素,插入到有序區的位置,直到無序區變空 # 相似於玩紙牌時的插牌 # 能夠優化空間使用二分查找來尋找插入點(並無什麼卵用) def insert_sort(li): for i in range(1, len(li)): # 無序區 j = i-1 # 有序區最後一個數 tmp = li[i] while j >= 0 and li[j] > tmp: # 有序區從大到小逐一比較,直到有序區數小於li[i] li[j+1] = li[j] j -= 1 li[j+1] = tmp 牛逼三人組(o(nlogn)) 快排 # 取一個元素p(第一元素),使元素p歸位 # 列表被p分爲兩部分,左邊的都比p小,右邊的都比p大 # 遞歸完成排序 def _quick_sort(li, left, right): if left < right: # 至少兩個元素 mid = partition(li, left, right) _quick_sort(li, left, mid-1) _quick_sort(li, mid+1, right) def quick_sort(li): _quick_sort(li, 0, len(li)-1) def partition(li, left, right): i = random.randint(left, right) # 隨機選一個數,防止最壞狀況 li[left], li[i] = li[i], li[left] tmp = li[left] while left < right: while left < right and li[right] >= tmp: #從右開始選,直到找到一個小於tmp的數,把這個數填在left位置 right -= 1 li[left] = li[right] while left < right and li[left] <= tmp: #從左開始選,直到找到一個大於tmp的數,把這個數填在right位置 left += 1 li[right] = li[left] li[left] = tmp return left # 一行代碼實現快排 # 這樣空間複雜度會高 def quicksortshort(arr): return [] if arr==[] else quicksortshort([y for y in arr[1:] if y<arr[0]]) + [arr[0]]+ quicksortshort([y for y in arr[1:] if y>=arr[0]]) 堆排 # 1,創建堆 # 2,獲得堆頂元素,爲最大元素 # 3,去掉堆頂,將堆最後一個元素放到堆頂,此時可經過一個調整從新使堆有序 # 4,堆頂元素爲第二大元素 # 5,重複步驟3,直到堆變空 def sift(li, low, high): # 調整,從子孩子中選出最大的和父節點比較,若是大於父節點就和父節點的值交換,而後父節點的值繼續和子節點的子節點進行比較 # low 表示根位置 high 表示最後元素的位置 tmp = li[low] i = low # i指向空位 j = 2 * i + 1 # j指向孩子 # 把tmp寫回來有兩種條件 1. tmp > li[j] 2. j位置沒有值 (也就是i已是葉子了) while j <= high: # 對應退出條件2 if j + 1 <= high and li[j+1] > li[j]: # 若是右孩子存在且右孩子更大 j += 1 if li[j] > tmp: li[i] = li[j] i = j j = 2 * i + 1 else: # 對應退出條件1 break li[i] = tmp li = [3,5,6,2,0,4,1,9,8,7] def heap_sort(li): n = len(li) # 1. 創建堆 for low in range(n//2-1, -1, -1): # li = [3,5,6,2,0,4,1,9,8,7] ''' 3(索引0) 5(1) 6(2) 2(3) 0(4) 4(5) 1(6) 9(7) 8(8) 7(9) ''' # 如 n=10時,low的值依次是 4,3,2,1,0 從最後的非葉子節點開始調整 sift(li, low, n-1) print(li) # 此時的li已是一個大根堆了 # [9, 8, 6, 5, 7, 4, 3, 0, 1, 2] ''' 9(索引0) 8(1) 6(2) 5(3) 7(4) 4(5) 3(6) 0(7) 1(8) 2(9) ''' # 2. 挨個出數 退休-棋子-調整 for high in range(n-1, -1, -1): # high 的值 9,8,7,6,,5,4,3,2,1,0 li[0], li[high] = li[high], li[0] # 這樣交換後最大的就變到了列表的最後位置上, sift(li, 0, high-1) # 而後調整的時候就不把已經退休的(最大的)考慮在內了 python內置的堆模塊 import heapq li = [2,5,7,8,9,6,1,4,3] heapq.heapify(li) #調整變爲小根堆 print(li) # [1, 3, 2, 4, 9, 6, 7, 5, 8] heapq.heappush(li, 0) # 插入新值,自動調整爲小根堆 print(li) # [0, 1, 2, 4, 3, 6, 7, 5根堆, 8, 9] print(heapq.heappop(li)) # 堆頂退休(最小值),繼續調整爲小 print(heapq.heappop(li)) print(heapq.nlargest(5, li)) # 輸出最大的5個數 # [9, 8, 7, 6, 5] print(heapq.nsmallest(5, li)) # 輸出最小的5個數 # [2, 3, 4, 5, 6] 列表中取出前k大的數 # 1,取列表前k個元素創建一個小根堆,堆頂就是這個堆中最小的數,也是這個堆中第k大的數 # 2,依次向後遍歷原列表,對於列表中的元素,若是小於堆頂,則忽略該元素,若是大於堆頂則將堆頂更換爲改元素,而且對堆進行一次調整 # 3,遍歷列表全部元素後,倒序彈出堆頂 歸併 def merge(li, low, mid, high): li_tmp = [] i = low j = mid + 1 while i <= mid and j <= high: if li[i] <= li[j]: li_tmp.append(li[i]) i += 1 else: li_tmp.append(li[j]) j += 1 while i <= mid: li_tmp.append(li[i]) i += 1 while j <= high: li_tmp.append(li[j]) j += 1 for i in range(len(li_tmp)): # 把歸併排好的兩個列表放回到li中 li[i+low] = li_tmp[i] def _merge_sort(li, low, high): if low < high: # 2個元素及以上 mid = (low + high) // 2 _merge_sort(li, low, mid) _merge_sort(li, mid+1, high) #print(li[low:mid+1], li[mid+1:high+1]) merge(li, low, mid, high) #print(li[low:high + 1]) def merge_sort(li): _merge_sort(li, 0, len(li)-1) 沒什麼人用的排序 基數排序 希爾排序 桶排序 二叉樹 列表中索引:父節點 -> 左孩子節點 i -> 2i+1 父節點 -> 右孩子節點 i -> 2i+2 孩子節點 -> 父節點 i -> (i-1)//2 堆頂 i = 0 全部父節點 i_list =[i for i in range(len(li)//2)] 大根堆:一個徹底二叉樹,知足任一節點都比其孩子節點大 小根堆:一個徹底二叉樹,知足任一節點都比其孩子節點小 當根節點的左右子樹都是堆時(這裏的示例是大根堆),能夠經過一次向下調整來將其變換成一個堆