Task 03:数组排序(day4)

Task 03: 数组排序

第7天打卡,附上学习链接

1 学习内容

1.1 计数排序(Counting Sort)

使用一个额外的数组counts,其中第i个元素count[i]是待排序数组arr中值等于i的元素个数,然后根据数组counts来将arr中的元素排到正确的位置。

算法步骤:

  • (1)找出待排序数组中最大值元素和最小值元素;

  • (2)统计数组中每个值为i的元素出现的次数,存在数组的第i项;

  • (3)对所有计数累加(从counts中的第一个元素开始,每一项和前一项累加);

  • (4)反向填充目标数组:将每个元素i放在新数组的第counts[i]项,每放一个元素就要将counts[i] -= 1。

算法分析:

  • 当输入元素是n个0~k之间的整数时,计数排序的时间复杂度为O(n+k);

  • 由于用于计数的数组counts的长度取决于待排序数组中数据的范围(等于待排序数组最大值减去最小值再加1),所以计数排序对于数据范围很大的数组,需要大量的时间和内存;

  • 计数排序一般用于排序整数,不适用于按字母顺序排序人名;

  • 计数排序时稳定排序算法。

代码实现:

def countingSort(arr):
    arr_min, arr_max = min(arr), max(arr)
    size = arr_max - arr_min + 1
    counts = [0 for _ in range(size)]
    
    for num in arr:
        counts[num - arr_min] += 1
    for j in range(1, size):
        counts[j] += counts[j - 1]
    
    res = [0 for _ in range(len(arr))]
    for i in range(len(arr) - 1, -1, -1):
        res[counts[arr[i] - arr_min] - 1] = arr[i]
        counts[arr[i] - arr_min] -= 1
    
    return res  
1.2 桶排序(Bucket Sort)

将未排序的数组分到若干个桶中,每个桶的元素再进行单独排序。

算法步骤:

  • (1)将区间划分为n个相同大小的子区间,每个区间称为一个桶;

  • (2)遍历数组,将每个元素装入对应的桶中;

  • (3)对每个桶内的元素单独排序(使用插入、归并、快排等算法);

  • (4)最后按照顺序将桶内的元素合并起来。

算法分析:

  • 桶排序可以在线性时间内完成排序,当输入元素个数为n,桶的个数是m时,桶排序时间复杂度为O(m+n);

  • 由于桶排序使用了辅助空间,所以空间复杂度是O(n+m);

  • 如果桶内使用插入排序等稳定排序算法,则桶排序也是稳定排序算法。

代码实现:

def insertionSort(arr):
    for i in range(1, len(arr)):
        temp = arr[i]
        j = i
        while j > 0 and arr[j - 1] > temp:
            arr[j] = arr[j - 1]
            j -= 1
        arr[j] = temp
        
    return arr
    
    
def bucketSort(arr, bucket_size = 5):
    arr_min, arr_max = min(arr), max(arr)
    bucket_count = (arr_max - arr_min) // bucket_size + 1
    buckets = [[] for _ in range(bucket_count)]
    
    for num in arr:
        buckets[(num - arr_min) // bucket_size].append(num)
        
    res = []
    for bucket in buckets:
        insertionSort(bucket)
        res.extend(bucket)
    
    return res 
1.3 基数排序(Radix Sort)

将整数按位数切割成不同的数字,然后按每个位数分别比较进行排序。

算法步骤:基数排序算法可以采用最低位优先法(Least Significant Digit First)或者最高位优先法(Most Significant Digit first),最常用的是前者。

  • (1)遍历数组元素,获取数组最大值元素,并取得位数;

  • (2)以个位元素为索引,对数组元素排序;

  • (3)合并数组;

  • (4)之后依次以十位、百位...,直到最大值元素的最高位处值为索引,进行排序,并合并数组,最终完成排序。

算法分析:

  • 基数排序的时间复杂度是O(k*n),其中n是待排序元素的个数,k是数字位数。k的大小取决于数字位的选择(十进制位、二进制位)和待排序元素所属数据类型全集的大小;

  • 基数排序的空间复杂度是O(n+k);

  • 基数排序是稳定排序算法。

代码实现:

def radixSort(arr):
    size = len(str(max(arr)))
    
    for i in range(size):
        buckets = [[] for _ in range(10)]
        for num in arr:
            buckets[num // (10**i) % 10].append(num)
        arr.clear()
        for bucket in buckets:
            for num in bucket:
                arr.append(num)
            
    return arr

2 练习题目

2.1 1122 数组的相对排序 *

题目描述:给出两个数组arr1和arr2,arr2中的元素各不相同,arr2中的每个元素都出现在arr1中,对arr1中的元素进行排序,使arr1中项的相对顺序和arr2中的相对顺序相同。未在arr2中出现过的元素需要按照升序放在arr1的末尾。 样例1:输入为arr1=[2, 3, 1, 3, 2, 4, 6, 7, 9, 2, 19], arr2=[2, 1, 4, 3, 9, 6],输出为[2, 2, 2, 1, 4, 3, 3, 9, 6, 7, 19]。

解题思路:自定义排序。

class Solution:
    def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
        def mycmp(x: int) -> (int, int):
            return (0, rank[x]) if x in rank else (1, x)
        
        rank = {x: i for i, x in enumerate(arr2)}
        arr1.sort(key=mycmp)
        return arr1

时间复杂度:O(mlogm+n); 空间复杂度:O(logm+n)。

2.2 0908 最小差值I *

题目描述:一个整数数组nums,给每个元素都加上一个任意数字x(-k<=x<=k),从而得到一个新数组result。返回数组result的最大值和最小值之间可能存在的最小差值。 样例1:输入为nums=[1], k=0,输出0; 样例2:输入为nums=[0, 10],k=2,输出为6; 样例3:输入为num=[1, 3, 6],k=3,输出为0。

解题思路:求B最大与最小之间的最小差值,希望的是max(B)更小,min(B)更大。max(B)最小的极 限值是max(A)-k,min(B)最大的极限值是min(A)+k,所以最小差值至少为(max(A)-k) - (min(A)+k)。

class Solution:
    def smallestRangeI(self, nums: List[int], k: int) -> int:
        return max(0, max(A)-min(A) - 2*k)

时间复杂度:O(n); 空间复杂度:O(1)。

2.3 0164 最大间距 ***

题目描述:给一个无序数组nums,要找出数组在排序之后,相邻元素之间最大的差值。如果数组元素个数小于2,则返回0。 样例1:输入为arr=[3, 2, 1], k=2,输出为[1, 2]或[2, 1]; 样例2:输入为arr=[0, 1, 2, 1], k=1,输出为[0]。

解题思路:基数排序,元素个数小于2的单独处理。

class Solution:
    def radixSort(arr):
        size = len(str(max(arr)))

        for i in range(size):
            buckets = [[] for _ in range(10)]
            for num in arr:
                buckets[num // (10**i) % 10].append(num)
            arr.clear()
            for bucket in buckets:
                for num in bucket:
                    arr.append(num)

        return arr
    
    def maximumGap(self, nums: List[int]) -> int:
        if len(nums) < 2:
            return 0
        arr = self.radixSort(nums)
        return max(arr[i] - arr[i-1] for i in range(1, len(arr)))
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容