LeetCode之算法面试之数组2之颜色分类(75)、合并两个有序数组(88)、数组中的第k个最大元素(215)


————技巧点:快排思想

1、颜色分类(75)

题目描述:

【中等题】

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

注意:
不能使用代码库中的排序函数来解决这道题。

在这里插入图片描述

题目链接

思路分析

要求:对仅含有数字0,1,2的数组排序。
特点:数字重复率极高

题解一:计数排序

1、遍历数组,统计0,1,2分别出现的总个数
2、遍历数组,依次将0,1,2填充进去。

【python代码实现】

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        #统计0,1,2的次数
        zero=nums.count(0)
        one=nums.count(1)
        two=nums.count(2)
        index=0 #填充移动指针
        for i in range(zero):
            nums[index]=0
            index+=1
        for i in range(one):
            nums[index]=1
            index+=1
        for i in range(two):
            nums[index]=2
            index+=1
  • 时间复杂度: O ( n ) O(n) O(n),遍历两遍数组

  • 空间复杂度: O ( 1 ) O(1) O(1)

此方法遍历了两遍数组,能不能就遍历一遍数组呢?当然能,并且考虑数组元素重复率较高,我们可以使用三路快排的方法。

题解二:三路快排

具体原理、思想见上一篇博文快排(单路、双路、三路)详解

1、该数组只有0,1,2三种元素,因此我们可以以1为基准元素,所有等于2的元素放在右边,等于0的元素放在左边。
2、设置分界指针zero,two
未完待续

在这里插入图片描述
【python代码实现】

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        '''
        all in [0, zero) = 0
        all in [zero, i) = 1
        all in [two, len(nums) - 1] = 2
        '''
        zero=-1 # nums[0...zero]=0,0与1的分解指针初始化为-1,保证其刚开始是无效数组
        two=len(nums) # nums[two...len(nums)-1]=2,1与2的分界指针初始化为长度,保证其刚开始是无效数组
        i=0
        while i<two:
            if nums[i]==1:
                i+=1
            elif nums[i]==0:
                zero+=1
                nums[i],nums[zero]=nums[zero],nums[i]
                i+=1
            else: # nums[i]==2
                two-=1
                nums[i],nums[two]=nums[two],nums[i]

2、合并两个有序数组(88)

题目描述:

【简单题】

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

说明:

初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

在这里插入图片描述

题目链接

思路分析

要求:两个有序数组合并到其中一个数组内。

题解一:合并后排序

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        nums1[:]=sorted(nums1[:m]+nums2)#注意:nums1取前m个元素
  • 时间复杂度: O ( ( m + n ) l o g ( m + n ) ) O((m+n)log(m+n)) O((m+n)log(m+n))
  • 空间复杂度: O ( 1 ) O(1) O(1)

缺点:时间复杂度大,没有利用两个数组本身就有序这一点

题解二:双指针—从前往后

\quad \quad 其实,有序合并两次可以想到用归并排序的归并操作来解答此题。

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        p1=0
        p2=0
        nums1_copy=nums1[:m]#额外的空间将nums1中的元素腾出来
        nums1[:]=[]
        while p1<m and p2<n:#两数组都不为空时
            if nums1_copy[p1]<nums2[p2]:#谁小先放谁
                nums1.append(nums1_copy[p1])
                p1+=1
                
            else:
                nums1.append(nums2[p2])
                p2 += 1
        if p1<m:#nums2数组已处理完
            nums1[p1+p2:]=nums1_copy[p1:]
        if p2<n:#nums1数组已处理完
            nums1[p1+p2:]=nums2[p2:]
  • 时间复杂度: O ( n + m ) O(n+m) O(n+m)
  • 空间复杂度: O ( m ) O(m) O(m),由于nums1是用于输出的数组,需要将nums1中的前m个元素放在其他地方,另两个指针

题解三:双指针—从后往前

\quad \quad 为了解决省略上一题解所需的额外空间,可以考虑从后往前走,因为nums1的空间都在后面,所以从后向前处理排序的数据会更好,节省空间,一边遍历一边将值填充进去。

  • 设置指针p1p2分别指向nums1nums2的有数字尾部即p1=m-1p2=n-1

  • 设置指针k指向nums1的最末尾,(每次遍历比较两数组值大小后,则进行填充)即k=m+n-1

  • 当p1>0且p2>0:
    比较两数组相对应位置大小,大的填充在nums1[k]处且相应的指针-1,k-1

  • p1<0:此时nums2中数据未拷贝完,
    将nums2中数据直接拷贝到nums1的前面

  • 否则即p2<0:此时nums1中数据未拷贝完,但是因为其在nums1中,故什么都不用做

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        p1=m-1        #p1指向nums1有数字末尾处
        p2=n-1        #p1指向nums2末尾处
        k=m+n-1       #k指向nums1末尾处
        while p1>=0 and p2>=0:
            if nums1[p1]>nums2[p2]:
                nums1[k]=nums1[p1]
                p1-=1
                k-=1
            else:
                nums1[k]=nums2[p2]
                p2-=1
                k-=1
        if p1<0:        #nums2中还有书数据没有拷贝完
            nums1[:p2+1]=nums2[:p2+1]

3、数组中的第k个最大元素(215)

题目描述:

【中等题】
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

在这里插入图片描述
题目链接
思路分析

要求:求排序后的第k大元素

题解一:暴力法

python函数排序,再求k索引

1、基于python排序函数对数组升序
2、返回**nums[-k]**即为排序后的第k大元素

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        nums.sort()
        return nums[-k]
  • 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
  • 空间复杂度:O(1),这里是原地排序,没有借助额外的辅助空间。

\quad \quad python里的sort排序是一种名为Timsort的排序方法,其时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),而且这是一种快速的稳定的排序方法。它的发明者是Tim Peters在2001年为Python创造的一种排序算法。

题解二:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值