腾讯算法岗面试算法题——计数排序

给定两个整数数组,对第一个数组进行排序,整数顺序由其在第二个数组中的位置决定。对于没有出现在
第二个整数数组中的整数,应排在末尾,其之间的顺序无限制。这里整数的取值范围是[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,这样的代价才应该是最低的,无论从空间复杂性还是时间复杂性来说。

 

# -*- 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_one_time(array, flag):
    # print array
    if len(array) <= 1:
        return

    low = 0
    high = len(array) - 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]

    return low


def func(list1, list2):
    global num2index
    for index, num in enumerate(list2):
        num2index[num] = index
    index = quicksort_one_time(list1, list2[-1])
    left, right = list1[:index + 1], list1[index + 1:]
    num2count = dict()
    for i in left:
        if num2count.has_key(i):
            num2count[i] += 1
        else:
            num2count[i] = 1
    result = []
    for num in list2:
        if num2count[num] != 0:
            for _ in range(num2count[num]):
                result.append(num)
    return result + right


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

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

 

posted on 2018-08-20 20:45  法杰拉  阅读(1162)  评论(0编辑  收藏  举报

导航