python代碼 程序員編程藝術 2.1

首先一般考慮“萬能的”暴力窮舉(遞歸、回溯)。但因爲窮舉時間複雜度通常過高,所以需要考慮更好的方法,如分治法(通過分而治之,然後歸併),以及空間換時間(如活用哈希表)。

此外,選擇合適的數據結構可以顯著提升效率,如尋找最小的k個數中,用堆代替數組。

再有,如果題目允許排序,則可以考慮排序。比如,尋找和爲定值的兩個數中,先排序,然後用前後兩個指針往中間掃。而如果如果已經排好序了(如楊氏矩陣查找中),則想想有無必要二分。但是,如果題目不允許排序呢?這個時候,我們可以考慮不改變數列順序的貪心算法(如最小生成樹Prim、Kruskal及最短路dijkstra),或動態規劃(如 01揹包問題,每一步都在決策)。

2.1 尋找最小的k個數:解法1, 解法4

快速排序使用分治法(Divide and conquer)策略來把一個序列(list)分爲兩個子序列(sub-lists)。

步驟爲:

  1. 從數列中挑出一個元素,稱爲"基準"(pivot),
  2. 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分區退出之後,該基準就處於數列的中間位置。這個稱爲分區(partition)操作。
  3. 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。
import random
import timeit
 
def quickSort(numbers):
    if len(numbers) <= 1:
        return numbers
 
    pivot = random.choice(numbers)
    less = [i for i in numbers if i < pivot]
    equal = [i for i in numbers if i == pivot]
    greater = [i for i in numbers if i > pivot]
    return quickSort(less) + equal + quickSort(greater)
 
def quickSelect(numbers, k):
    pivot = random.choice(numbers)
    less = [i for i in numbers if i < pivot]
    equal = [i for i in numbers if i == pivot]
    greater = [i for i in numbers if i > pivot]
 
    if k <= len(less):
        return quickSelect(less, k)
    elif k <= len(less) + len(equal):
        return less + equal
    else:
        return less + equal + quickSelect(greater, k - len(less) - len(equal))
 
def main():
    k = 3
    numbers = [18, 27, 9, 65, 33]
 
    tmpNumbers = quickSort(numbers)
    print tmpNumbers[:k]
 
    tmpNumbers = quickSelect(numbers, k)
    print tmpNumbers
 
if __name__ == '__main__':
    main()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章