1. 程式人生 > >騰訊算法崗一面算法題——計數排序

騰訊算法崗一面算法題——計數排序

sort space oat ret light 函數 class 兩個 not

給定兩個整數數組,對第一個數組進行排序,整數順序由其在第二個數組中的位置決定。對於沒有出現在
第二個整數數組中的整數,應排在末尾,其之間的順序無限制。這裏整數的取值範圍是[0, 2 ^ 32 - 1]

例: 第一個整數數組為 5 1 6 2 1 2 3, 第二個整數數組為2 1 3, 則排序結果為2 2 1 1 3 6 5或2 2 1 1 3 5 6

這道題很明顯的第一個思路就是,先生成一個數到index下標的映射,然後建立一個compare函數,根據這個compare函數寫一個快排。

相關代碼如下:

# -*- coding:utf-8 -*-

num2index = dict()


def cmp(a, b):
    if a not in num2index and b not in num2index:
        return 0
    elif a not in num2index:
        return 1
    elif b not in num2index:
        return -1
    else:
        if num2index[a] < num2index[b]:
            return -1
        elif num2index[a] == num2index[b]:
            return 0
        else:
            return 1


def quicksort(array, begin, end):
    # print array
    if end - begin <= 1:
        return
    elif end - begin == 2:
        if cmp(array[begin], array[begin + 1]) > 0:
            array[begin], array[begin + 1] = array[begin + 1], array[begin]
        return
    flag = array[begin]
    low = begin + 1
    high = end - 1
    while (low < high):
        while low < high and cmp(array[high], flag) > 0:
            high -= 1
        while low < high and cmp(array[low], flag) <= 0:
            low += 1
        if low != high:
            array[low], array[high] = array[high], array[low]
    if high == low == begin + 1:
        quicksort(array, begin + 1, end)
    else:
        array[begin], array[high] = array[high], array[begin]
        quicksort(array, begin, high)
        quicksort(array, high + 1, end)


def func(list1, list2):
    global num2index
    for index, num in enumerate(list2):
        num2index[num] = index
    # sorted(list1, cmp=cmp)
    quicksort(list1, 0, len(list1))
    print list1


if __name__ == "__main__":
    list1 = [5, 1, 6, 2, 1, 2, 3]
    list2 = [2, 1, 3]
    func(list1, list2)

這個代碼提交給面試官,面試官問了一下時間復雜度,顯然快排的時間復雜度是nlog(n),面試官讓我改成線性時間,o(╯□╰)o,抱歉當時那幾個線性排序的算法都不記得了,面試官提醒了一下用count sort ,當時想不起來了。

回去的時候才想了一下。純整數的排序,確實能夠利用空間換時間,得到線性的時間復雜度。先遍歷list1,建立一個num到count的映射,然後遍歷list2,直接每個數字出現了多少次就加幾個到結果中。同時把對應的count置為0,然後在遍歷一遍num2count,對應value不是0的,加入value個鍵值。最後返回result

# -*- coding:utf-8 -*-


def func(list1, list2):
    num2count = dict()
    for num in list1:
        if num2count.has_key(num):
            num2count[num] += 1
        else:
            num2count[num] = 1

    result = []
    for num in list2:
        for _ in range(num2count[num]):
            result.append(num)
        num2count[num] = 0
    for num in num2count:
        if num2count[num] != 0:
            for _ in range(num2count[num]):
                result.append(num)
    print result


if __name__ == "__main__":
    list1 = [5, 1, 6, 2, 1, 2, 3]
    list2 = [2, 1, 3]
    func(list1, list2)

後面又回去想了想,好像還可以繼續優化,第一遍利用快排的思想,把list1變成左邊是在list2中出現過的數,右邊是沒有出現過的數。於是右邊本來就是無序的,就可以直接對左邊部分進行count sort,這樣的代價才應該是最低的,無論從空間復雜性還是時間復雜性來說。

騰訊算法崗一面算法題——計數排序