Pyton:912. 排序数组 —— 给你一个整数数组 nums,请你将该数组升序排列

@创建于:2021.11.18

LeeCode 912. 排序数组
给你一个整数数组 nums,请你将该数组升序排列。
https://leetcode-cn.com/problems/sort-an-array/submissions/

1、python自带排序

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        return sorted(nums)

3、插入排序

3.1 算法思想

插入排序(Insertion Sort)基本思想:
将整个序列切分为两部分:前 i - 1 个元素是有序序列,后 n - i + 1 个元素是无序序列。每一次排序,将无序序列的首元素,在有序序列中找到相应的位置并插入。
插入排序方法属于稳定性排序方法。
算法时间复杂度: O ( n 2 ) O(n^2) O(n2)
算法空间复杂度: O ( 1 ) O(1) O(1)

3.2 步骤与演示

  • 将第一个元素作为一个有序序列,将第 2 ~ n - 1 个元素作为无序序列。
  • 从头至尾一次扫描无序序列,将扫描到的每个元素插入到有序序列的适当位置上。

在这里插入图片描述

3.3 代码实践

LeeCode显示超时!

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        n = len(nums)
        
        for i in range(n):
            tmp = nums[i]
            j = i

            while (j>0) and (nums[j-1]>tmp):
                nums[j] = nums[j-1]
                j -= 1
            nums[j] = tmp
        return nums

4、希尔排序

4.1 算法思想

希尔排序(Shell Sort)基本思想:
将整个序列切按照一定的间隔取值划分为若干个子序列,每个子序列分别进行插入排序。然后逐渐缩小间隔进行下一轮划分子序列和插入排序。直至最后一轮排序间隔为 1,对整个序列进行插入排序。
希尔排序方法是一种不稳定排序算法。
算法时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n 2 ) O(n^2) O(n2)之间
算法空间复杂度: O ( 1 ) O(1) O(1)

4.2 步骤与演示

  • 首先确定一个元素间隔数 gap,然后将参加排序的序列按此间隔数从第 1 个元素开始一次分成若干个子序列,即分别将所有位置相隔为 gap 的元素视为一个子序列,在各个子序列中采用某种排序方法进行插入排序。
  • 然后减少间隔数,并重新将整个序列按新的间隔数分成若干个子序列,再分别对各个子序列进行排序,如此下去,直到间隔数 gap = 1。

在这里插入图片描述

4.3 代码实践

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        n = len(nums)
        gap = n // 1
        
        while gap>0:
            for i in range(gap, n):
                tmp = nums[i]
                j = i

                while (j>0) and (nums[j-gap]>tmp):
                    nums[j] = nums[j-gap]
                    j -= gap
                nums[j] = tmp
            gap = gap // 2
        return nums

5、归并排序

5.1 算法思想

归并排序(Merge Sort)基本思想:
采用经典的分治策略,先递归地将当前序列平均分成两半。然后将有序序列两两合并,最终合并成一个有序序列。
归并排序算法是 稳定排序算法。
算法时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
算法空间复杂度: O ( n ) O(n) O(n)

5.2 步骤与演示

  • 初始时,将待排序序列中的 n 个记录看成 n 个有序子序列(每个子序列总是有序的),每个子序列的长度均为 1。
  • 把当前序列组中有序子序列两两归并,完成一遍之后序列组里的排序序列个数减半,每个子序列的长度加倍。
  • 对长度加倍的有序子序列重复上面的操作,最终得到一个长度为 n 的有序序列。

在这里插入图片描述

5.3 代码实践

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:

        def merge(left_arr, right_arr):
            arr = []
            while left_arr and right_arr:
                if left_arr[0] <= right_arr[0]:
                    arr.append(left_arr.pop(0))
                else:
                    arr.append(right_arr.pop(0))
            
            while left_arr:
                arr.append(left_arr.pop(0))
            while right_arr:
                arr.append(right_arr.pop(0))
            return arr
        
        def merge_sort(arr):
            n = len(arr)
            if n < 2:
                return arr
            mid = n // 2
            left_arr = arr[:mid]
            right_arr = arr[mid:]
            return merge(merge_sort(left_arr), merge_sort(right_arr))
        
        return merge_sort(nums)

6. 快速排序

6.1 算法思想

通过一趟排序将无序序列分为独立的两个序列,第一个序列的值均比第二个序列的值小。然后递归地排列两个子序列,以达到整个序列有序。

6.2 步骤与演示

  • 挑选基准值:从数列中挑出一个元素,称为"基准"(pivot);
  • 分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成;
  • 递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。

在这里插入图片描述其实动图,我并没有看太明白。下面两个链接,我认为是比较好的。
快速排序算法详解(原理、实现和时间复杂度)
http://data.biancheng.net/view/117.html
快速排序算法
https://www.bilibili.com/video/BV1at411T75o/

6.3 代码实践

下面显示提交超时。参考代码:Python实现快速排序算法

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        
        def quick_sort(arr, left, right):
            if left > right:
                return arr
            
            pivot = arr[left]
            i = left
            j = right

            while left < right:
                while (left<right) and (arr[right]>=pivot):
                    right -= 1
                arr[left] = arr[right]

                while (left<right) and (arr[left]<=pivot):
                    left += 1
                arr[right] = arr[left]
                
            arr[right] = pivot
            quick_sort(arr, i, left-1)
            quick_sort(arr, left+1, j)
        
        quick_sort(nums, 0, len(nums)-1)
        return nums

7. 堆排序

7.1 算法思想

借用「堆结构」所设计的排序算法。将数组转化为大顶堆,重复从大顶堆中取出数值最大的节点,并让剩余的堆维持大顶堆性质。
堆:符合以下两个条件之一的完全二叉树:
大顶堆:根节点值 ≥ 子节点值。
小顶堆:根节点值 ≤ 子节点值。

算法时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
算法空间复杂度: O ( 1 ) O(1) O(1)

7.2 步骤与演示

在这里插入图片描述

7.3 代码实践

看的别人的代码,没看懂的。堆排序

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        
        # 调整为大顶堆
        def heapify(arr: [int], index: int, end: int):
            left = index * 2 + 1
            right = left + 1

            while left <= end:
                # 当前节点为非叶子结点
                max_index = index
                if arr[left] > arr[max_index]:
                    max_index = left
                if right<=end and arr[right]> arr[max_index]:
                    max_index = right
                if index == max_index:
                    # 如果不用交换,则说明已经交换结束
                    break
                arr[index], arr[max_index] = arr[max_index], arr[index]
                # 继续调整子树
                index = max_index
                left = index*2 + 1
                right = left + 1
        
        # 初始化大顶堆
        def buildMaxHeap(arr: [int]):
	        size = len(arr)
	        # (size-2) // 2 是最后一个非叶节点,叶节点不用调整
	        for i in range((size - 2) // 2, -1, -1):
		        heapify(arr, i, size - 1)
	        return arr

        def maxHeapSort(arr: [int]):
	        buildMaxHeap(arr)
	        size = len(arr)
	        for i in range(size):
		        arr[0], arr[size-i-1] = arr[size-i-1], arr[0]
		        heapify(arr, 0, size-i-2)
	        return arr
        return maxHeapSort(nums)

8. 计数排序

8.1 算法思想

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

8.2 步骤与演示

找出待排序数组中最大值元素和最小值元素。
统计数组中每个值为 i 的元素出现的次数,存入数组的第 i 项。
对所有的计数累加(从 counts 中的第一个元素开始,每一项和前一项累加)。
反向填充目标数组:将每个元素 i 放在新数组的第 counts[i] 项,每放一个元素就要将 counts[i] -= 1。

当输入元素是 n 个 0 ~ k 之间的整数时,计数排序的时间复杂度为 。
如果不考虑结果数组,只考虑中间数组大小的话,空间复杂度是O(M)在这里插入图片描述
下面这个图来源:python实现·十大排序算法之计数排序(Counting Sort)
在这里插入图片描述
局限性
当数列的最大和最小值差距过大时,并不适用计数排序
当数列元素不是整数,并不适用计数排序

8.3 代码实践

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        
        arr_min, arr_max = min(nums), max(nums)
        size = arr_max - arr_min + 1
        counts = [0]*size

        # 第一次循环遍历
        for num in nums:
            counts[num-arr_min] += 1
        
        # 第二次循环遍历
        for j in range(1, size):
            counts[j] = counts[j] + counts[j-1]
        
        # 第三次循环遍历,为什么是逆序,正序我试验过,不对!
        res = [0]*len(nums)
        for i in range(len(nums)-1, -1, -1):
            index = counts[nums[i]-arr_min] - 1
            res[index] = nums[i]
            counts[nums[i]-arr_min] -= 1
        return res

之所以要获取arr的最大值和最小值,是因为需要排序的一定范围的整数不一定是从0开始,此时为避免空间位置浪费,中间数组的长度是是数列最大值和最小值的差+1,此时最小值作为一个偏移量存在

  • 第一次遍历:用来遍历arr的每个元素,统计每个元素的出现次数,存入中间数组(下标是arr中的元素值,值是该元素在arr中的出现次数)
  • 第二次遍历:遍历中间数组,每个位置的值=当前值+前一个位置的值,用来统计出小于等于当前下标的元素个数
  • 第三次遍历:反向遍历arr的每个元素,找到该元素值在中间数组的对应下标,以这个中间数组的值作为结果数组的下标,将该元素存入结果数组

9. 桶排序

9.1 算法思想

桶排序(Bucket Sort)基本思想:
将未排序的数组分到若干个「桶」中,每个桶的元素再进行单独排序。

9.2 步骤与演示

下图来源于:桶排序(python)
在这里插入图片描述
平均时间复杂度:O(n + k)
最佳时间复杂度:O(n + k)
最差时间复杂度:O(n ^ 2)
空间复杂度:O(n * k)
稳定性:稳定

9.3 代码实践

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        
        def insert_sort(arr):
            for i in range(1, len(arr)):
                tmp = arr[i]
                j = i
                while j>0 and arr[j-1]>tmp:
                    arr[j] = arr[j-1]
                    j -= 1
                arr[j] = tmp
            return arr
        
        def bucket_sort(arr, bucket_nums=5):
            arr_min, arr_max = min(arr), max(arr)
            # 因为向下取整,所以最后加1
            bucket_range = (arr_max - arr_min) // bucket_nums + 1
            buckets = [[] for i in range(bucket_range)]
            
            for value in arr:
                index = (value - arr_min) // bucket_nums
                buckets[index].append(value)
            
            res = []
            for bucket in buckets:
                res.extend(insert_sort(bucket))
            return res

        return bucket_sort(nums)

10. 基数排序

10.1 算法思想

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

10.2 步骤与演示

  • 遍历数组元素,获取数组最大值元素,并取得位数。
  • 以个位元素为索引,对数组元素排序。
  • 合并数组。
  • 之后依次以十位,百位,…,直到最大值元素的最高位处值为索引,进行排序,并合并数组,最终完成排序。

时间复杂度:O(k*N)
空间复杂度:O(k + N)
稳定性:稳定
下图来自:九大排序之——基数排序

在这里插入图片描述

10.3 代码实践

参考python实现·十大排序算法之基数排序(Radix Sort)

提交失败,因为leecode中有负数,该方法需要对负数单独排序,对正整数单独排序。

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        # 记录最大值的位数
        n_bit = len(str(max(nums)))

        for k in range(n_bit):
            # 第k轮排序, 生成10个列表
            bucket_list = [[] for _ in range(10)]
            for value in nums:
                # 按照第k位放到桶中
                bucket_list[value//(10**k)%10].append(value)

            # 按当前桶的顺序重排列表
            arr=[j for i in bucket_list for j in i]
            # arr = []
            # for item in bucket_list:
            #     for value in item:
            #         arr.append(value)
        return arr

11、506. 相对名次

给出 N 名运动员的成绩,找出他们的相对名次并授予前三名对应的奖牌。前三名运动员将会被分别授予 “金牌”,“银牌” 和“ 铜牌”(“Gold Medal”, “Silver Medal”, “Bronze Medal”)。
(注:分数越高的选手,排名越靠前。)
https://leetcode-cn.com/problems/relative-ranks/

class Solution:
    def findRelativeRanks(self, score: List[int]) -> List[str]:
        # 1.使用enumerate同时获得元素和索引;
        # 2.sorted对元组排序,按照 成绩 排序
        # 3.获取元组的第一个元素,即索引值,对score重新赋值
        res = sorted(list(enumerate(score)), key=lambda x:x[1], reverse=True)
        for i in range(len(res)):
            if i == 0:
                score[res[i][0]] = 'Gold Medal'
            elif i == 1:
                score[res[i][0]] = 'Silver Medal'
            elif i == 2:
                score[res[i][0]] = 'Bronze Medal'
            else:
                score[res[i][0]] = str(i+1)
        return score

12、剑指 Offer 51. 数组中的逆序对

下面这个通过了。归并思路。

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        self.n = 0

        def merge(arr, start, mid, end):
            i,j, tmp = start, mid+1, []
            while i<=mid and j<=end:
                if arr[i]<=arr[j]:
                    tmp.append(arr[i])
                    i += 1
                elif arr[i] > arr[j]:
                    tmp.append(arr[j])
                    j += 1
                    self.n += mid+1-i
            while i<=mid:
                tmp.append(arr[i])
                i += 1
            while j<=end:
                tmp.append(arr[j])
                j += 1
            
            for i in range(len(tmp)):
                nums[start+i] = tmp[i]
        
        def mergeSort(arr, start, end):
            if start >= end:
                return
            mid = (start+end) >> 1
            mergeSort(arr, start, mid)
            mergeSort(arr, mid+1, end)
            merge(arr, start, mid, end)
        
        mergeSort(nums, 0, len(nums)-1)
        return self.n

同样是归并思路,下面的显示:超出时间限制。不能理解。

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        self.n = 0

        def merge(left_arr, right_arr):
            arr = []
            while left_arr and right_arr:
                if left_arr[0] <= right_arr[0]:
                    arr.append(left_arr.pop(0))
                else:
                    arr.append(right_arr.pop(0))
                    self.n += len(left_arr)
            while left_arr:
                arr.append(left_arr.pop(0))
            while right_arr:
                arr.append(right_arr.pop(0))
            return arr

        def mergeSort(arr):
            size = len(arr)
            if size < 2:
                return arr
            mid = len(arr) // 2
            left_arr, right_arr = arr[0: mid], arr[mid:]
            return merge(mergeSort(left_arr), mergeSort(right_arr))
        
        mergeSort(nums)
        return self.n

13、75. 颜色分类

https://github.com/BreezePython/AlgorithmMarkdown

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        left, point, right = 0, 0, len(nums) - 1
        while point<=right: 
            if nums[point] == 0:
                nums[left], nums[point] = nums[point], nums[left]
                left += 1
                point += 1
            elif nums[point] == 2:
                nums[point], nums[right] = nums[right], nums[point]
                right -= 1
            else:
                point += 1

14、215. 数组中的第K个最大元素

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        def inset_sort(arr):
            for i in range(1, len(arr)):
                tmp = arr[i]
                j = i
                while j>0 and arr[j-1]>tmp:
                    arr[j] = arr[j-1]
                    j -= 1
                arr[j] = tmp
            return arr

        def bucket_sort(arr, bucket_nums=5):
            arr_min, arr_max = min(arr), max(arr)
            # 因为向下取整,所以最后加1
            bucket_range = (arr_max - arr_min) // bucket_nums + 1
            buckets = [[] for _ in range(bucket_range)]

            for value in arr:
                index = (value - arr_min) // bucket_nums
                buckets[index].append(value)
            
            res = []
            for bucket in buckets:
                res.extend(inset_sort(bucket))
            return res
        
        return bucket_sort(nums)[-k]

15、剑指 Offer 40. 最小的k个数

class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        def insert_sort(arr):
            for i in range(1, len(arr)):
                tmp = arr[i]
                j = i
                while j>0 and arr[j-1] > tmp:
                    arr[j] = arr[j-1]
                    j -= 1
                arr[j] = tmp
            return arr
        
        def bucket_sort(arr, bucket_num=5):
            arr_min, arr_max = min(arr), max(arr)
            # 因为向下取整,所以最后加1
            bucket_range = (arr_max - arr_min) // bucket_num + 1
            buckets = [[] for _ in range(bucket_range)]

            for value in arr:
                index = (value - arr_min) // bucket_num
                buckets[index].append(value)
            
            res = []
            for bucket in buckets:
                res.extend(insert_sort(bucket))
            return res
        return bucket_sort(arr)[:k]

16、1122. 数组的相对排序

class Solution:
    def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
        upper = max(arr1)
        frequence = [0]*(upper+1)
        for x in arr1:
            frequence[x] += 1
        
        res = list()
        for x in arr2:
            res.extend([x]*frequence[x])
            frequence[x] = 0

        for x in range(upper+1):
            if frequence[x] > 0:
                res.extend([x]*frequence[x])
        
        return res

17、908. 最小差值 I

这个题的重点在于 读懂题目

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

18、164. 最大间距

这个代码,超时了。时间复杂度不是O(N)

class Solution:
    def maximumGap(self, nums: List[int]) -> int:

        if len(nums) < 2:
            return 0
        if len(nums) == 2:
            return abs(nums[1] - nums[0])

        def insert_sort(arr):
            for i in range(1, len(arr)):
                tmp = arr[i]
                j = i
                while j>0 and arr[j-1]>tmp:
                    arr[j] = arr[j-1]
                    j -= 1
                arr[j] = tmp
            return arr
        
        def bucket_sort(arr, bucket_num=5):
            arr_min, arr_max = min(arr), max(arr)
            bucket_range = (arr_max - arr_min) // bucket_num + 1
            buckets = [[] for _ in range(bucket_range)]

            for value in arr:
                index = (value-arr_min) // bucket_num
                buckets[index].append(value)
            
            res = []
            for bucket in buckets:
                res.extend(insert_sort(bucket))
            return res
        
        sort_nums = bucket_sort(nums)
        
        bias = 0
        for i in range(1, len(nums)):
            tmp = sort_nums[i] - sort_nums[i-1] 
            if tmp> bias:
                bias = tmp
        return bias

利用基排序

class Solution:
    def maximumGap(self, nums: List[int]) -> int:

        if len(nums) < 2:
            return 0

        # 基数排序
        i = 0 # 记录当前正在排拿一位,最低位为1
        max_num = max(nums)  # 最大值
        j = len(str(max_num))  # 记录最大值的位数
        while i < j:
            bucket_list =[[] for _ in range(10)] #初始化桶数组
            for x in nums:
                bucket_list[int(x / (10**i)) % 10].append(x) # 找到位置放入桶数组
            # print(bucket_list)
            nums.clear()
            for x in bucket_list:   # 放回原序列
                for y in x:
                    nums.append(y)
            i += 1
        
        return max(nums[i] - nums[i-1] for i in range(1, len(nums)))
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值