【数据结构-leetcode系列】4.合并两个有序数组(No.88)

题目链接如下: 

88. 合并两个有序数组https://leetcode.cn/problems/merge-sorted-array/

方法总结:

(1)切片合并+排序

(2)双指针+比较大小,正向(按从小到大)/逆向(按从大到小)插入

读题,最简单的思路是合并数组后排序,这种方法速度和效率也比较高。参见解法1:

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[:]=nums1[:m]+nums2[:n]
        #print(nums1)
        nums1.sort()

写了个快排,不过明显比内置sort函数慢。。空间占用大很多,可以忽略。

【这里个人复习一下class类中函数相互调用的方法,一定要记得函数定义时候加上“self”,并且在相互调用的时候也使用self.defxx,否则会报错“nameXX not defined”】

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[:]=nums1[:m]+nums2[:n]
        #print(nums1)
        #nums1.sort()#python内置sort函数
        self.quicksort(nums1,0,len(nums1)-1)
    def quicksort(self, nums: List[int],start:int,end:int):#自定义快速排序
        if start>=end:#开始位置小于结束位置,就返回一次排序
            return
        left,right=start,end
        base=nums[start]#选定一个初始默认base
        while left<right:
            while nums[right]>=base and left<right:
                right-=1
            nums[left]=nums[right]
            while nums[left]<=base and left<right:
                left+=1
            nums[right]=nums[left]
        nums[left]=base
        self.quicksort(nums,start,left-1)#每次排序后的base处的索引-left之前排序
        self.quicksort(nums,left+1,end)#每次排序后的base处的索引-left之后排序
   

利用了两个数组都“分别为排序好的数组”,通过【双指针】直接比较大小,还可以这么写:

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.
        """
        i,j=0,0#定义初始指针
        new=[]
        #m=3,len(nums)=6
        while i<m or j<n:
            if i==m:#nums1中最后一位小于nums2中未排完的数
                new.append(nums2[j])
                j+=1
            elif j==n:#nums2中最后一位小于nums1中未排完的数
                new.append(nums1[i])
                i+=1
            elif nums1[i]<=nums2[j]:
                new.append(nums1[i])
                i+=1
            elif nums1[i]>nums2[j]:
                new.append(nums2[j])
                j+=1
                #print(j)
        nums1[:]=new
   

 但是上述方法需要开辟新的内存空间(防止新数据覆盖旧数据),那么可以考虑逆向思维,因为nums1是足够长的(m+n长度),逆双指针从尾部开始更新:

这种方法不会覆盖,因为极限情况,假如nums2全部排到尾部,那么也正好填充满,而假如nums1中有数值排到尾部,那么前面的空则+1,更大于nums2,而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.
        """
        #无需开辟新的空间,从后往前,从大到小进行更新
        i,j=m-1,n-1
        tail=m+n-1
        while i>=0 or j>=0:
            if i==-1:#当原m个nums1数组中都已排完,tail也已经到相应位置
                nums1[tail]=nums2[j]
                j-=1
            elif j==-1:
                nums1[tail]=nums1[i]
                i-=1
            elif nums1[i]>=nums2[j]:
                nums1[tail]=nums1[i]
                i-=1
            elif nums2[j]>nums1[i]:
                nums1[tail]=nums2[j]
                j-=1
            tail-=1

可以看到,这种方法明显速度高很多。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值