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

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

原文地址:https://www.cnblogs.com/hit-joseph/p/9507999.html

时间: 2024-08-01 01:53:37

腾讯算法岗一面算法题——计数排序的相关文章

【算法导论学习-014】计数排序(CountingSortTest)

参考:<算法导论>P194页 8.2节 Counting sort 1.Counting sort的条件 待排序数全部分布在0~k之间,且k是已知数:或者分布在min~max之间,等价于分布在0~max-min之间,max和min是已知数. 2.java 实现 /** * 创建时间:2014年8月17日 下午3:22:14 项目名称:Test * * @author Cao Yanfeng * @since JDK 1.6.0_21 类说明: 计数排序法,复杂度O(n), 条件:所有数分布在0

常见的排序算法(四)( 归并排序,计数排序 , 基数排序)

 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. (如果读者不太了解什么叫分治法,可以去看看<算法导论>第一二章.) 归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1:否则将第

算法导论--第八章、计数排序

一.计数排序的基本思想是:对每一个输入元素x,确定小于x的元素个数.利用这一信息,就可以直接把x放到它在输出数组中的位置上了.例如,如果有17个元素小于x,则将x放在第18个位置即可.但是当存在几个元素相同时,会稍许不同,否则中间会漏掉元素. 二.假设输入是一个数组A[1..n],A.length = n.另外数组B[1...n]存放排序的输出,C[0...k]提供临时的存储空间: 伪代码如下: 1 Counting-Sort(A, B, k) 2 for i <- 1 to k 3 do C[

排序算法的c++实现——计数排序

任何比较排序算法的时间复杂度的上限为O(NlogN), 不存在比o(nlgN)更少的比较排序算法.如果想要在时间复杂度上超过O(NlogN)的时间复杂度,肯定需要加入其它条件.计数排序就加入了限制条件,从而使时间复杂度为O(N). 计数排序的核心思想(来自算法导论):计数排序要求待排序的n个元素的大小在[0, k]之间,并且k与n在一个数量级上,即k=O(n).对于每一个输入元素x, 确定小于等于x的个数为i.利用这一信息,就可以把元素x放到输出数组的正确位置,即把元素x放到输出数组下标为i-1

计数排序 - 算法数据结构面试分享(五)

数组排序问题 - 计数排序 昨天我们留了一道题目"给你一个整型数组,里面出现的数在[0-100] 之间,能用最优化的方法帮我排序吗". 1. 确保我们理解了问题,并且尝试一个例子,确认理解无误. 这是一道排序算法题,我们学过很多排序的算法.不一样的是,它给定一个额外的条件,数组里的每个数字都在1-100之间.如果我们采取传统的排序算法,这个条件我们好像用不上.大家在面试的时候如果发现有条件没有用上,基本上我们给出的算法可能不是最优的,或者我们没有解决它最原始的需求.举个例子{50, 4

算法数据结构面试分享(六)数组排序问题(2) - 计数排序

数组排序问题(2) 昨天我们留了一道题目"给你一个整型数组,里面出现的数在[0-100] 之间,能用最优化的方法帮我排序吗". 1. 确保我们理解了问题,并且尝试一个例子,确认理解无误. 这是一道排序算法题,我们学过很多排序的算法.不一样的是,它给定一个额外的条件,数组里的每个数字都在1-100之间.如果我们采取传统的排序算法,这个条件我们好像用不上.大家在面试的时候如果发现有条件没有用上,基本上我们给出的算法可能不是最优的,或者我们没有解决它最原始的需求.举个例子{50, 46, 5

1099:零起点学算法06——再来一题除法算术题

1099: 零起点学算法06--再来一题除法算术题 Time Limit: 1 Sec  Memory Limit: 128 MB   64bit IO Format: %lldSubmitted: 4811  Accepted: 1917[Submit][Status][Web Board] Description 再来一题除法算术题 Input 没有输入 Output 输出8除以5,保留1位小数 Sample Output 1.6 Source 零起点学算法 1 # include <std

【数据结构】非比较排序算法(实现计数排序和基数排序)

● 计数排序 1.算法思想: 计数排序是直接定址法的变形.通过开辟一定大小的空间,统计相同数据出现的次数,然后回写到原序列中. 2.步骤: 1)找到序列中的最大和最小数据,确定开辟的空间大小. 2)开辟空间,利用开辟的空间存放各数据的个数. 3)将排好序的序列回写到原序列中. 具体实现如下: void CountSort(int *arr, int size) {  assert(arr);  int min = arr[0];  int max = arr[0];  int num = 0;

[经典算法]计数排序

概述: 计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出.它的优势在于在对一定范围内的集合排序时,它的复杂度为Ο(n+k)(其中k是元素的范围),快于任何比较排序算法. 计数排序本质上是通过计算无序集合中元素出现的次数来决定集合应该如何排序的. 例如一个数组{1, 4, 1, 2, 7, 5, 2},进行计数排序过程 1.使用Count数组记录元素次数 Index: 0 1 2 3 4 5 6 7 8 9 Count: 0 2 2 0 1 1 0