arrays合并两个数组_刷题小组|倒计时12天:合并两个有序数组

题目

今天的题目是:合并两个有序数组

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

说明:

  • 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
  • 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。  示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3
输出:[1,2,2,3,5,6]

解题思路

首先说一个最耍赖,但是背后隐藏着坑的一个解法:直接用python的内置函数

在python中,可以使用内置的全局sorted()方法对可迭代的序列排序生成新序列,也可以使用list内置的sort()方法进行配序。下面看一下两种方法的区别:

  • sorted()函数对所有可迭代的对象进行排序操作,排序后会返回一个新的对象。
  • sort()函数属于List,是在原列表进行排序操作,不会返回新对象。

对于本题来说,除了要你排序以外,还给了你两个很关键的信息:

  1. 入参中给出了m、n两个参数,n就是nums2的实际长度,而m时nums1中有效长度。为什么说是有效呢?这是因为“假设nums1有足够的空间”,实际上是一个很长的全0列表,因此要写注意nums1种的有效元素
  2. “使nums1成为一个有序数组”,也就是说所有的操作都是在nums1这个对象中进行的,对象的地址不能变!
class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
    nums1[:] = sorted(nums1[:m] + nums2)

为何要使用 nums1[:]? 是否可以将 nums1[:] 换为 nums1 ?

在信息2中,我们注意到,题目要求我们原地修改nums1对象,而不能新生成一个对象然后让nums1指向这一新对象。

注意在python3中,对象是一个盒子,有具体的地址,而变量名相当于是 "标签",可以贴在盒子上。我们需要辨析:nums1 = A 和 nums1[:] = A 的不同之处:

  • nums1 = A :更改 nums1 这一变量名所指向的对象。让 nums1 变量指向 A 所指向的对象
  • nums1[:] = A :对 nums1 指向的对象赋值。把 A 变量指向的对象的值逐个 copy 到 nums1 指向的对象中并覆盖 nums1 指向的对象的原来值

nums1[:] 等价于 nums1[0:len(nums1)] 相当于取 nums1 对应的对象的一个视图,通常用这个来改变原对象的某几位值。

比如有时候,我们用 A[:2] = [0,1], 来改变 A 所指向的 list 对象的前两个值。而如果用 A = [0,1], 则是让 A 这一变量名指向新的 list 对象 [0,1]

下面的代码则验证了上面的解释:

# 对象在内存中的地址与id 一一对应,可以使用 id() 查看并判断是否是同一个对象

nums1 = [1,2,4,0,0] 
print(id(nums1)) # 140125129895880

A = [1,2,3,4,5]
print(id(A))     # 140125129856640

nums1[:] = A
print(id(nums1))) # 140125129895880,  仍是原 list 对象, 只不过这一 list 对象的值发生了改变

# 若不执行 nums1[:] = A, 而执行
nums1 = A
print(id(nums1))  # 140125129856640, 不再是之前的那个 list 对象

示意图如下:

12ea020f1899246e1ac602ce1e0b3a0c.png

到这里我们就明白了为何要使用 nums1[:]。这里 sorted() 函数返回的必然是一个新的对象,因此我们需要 nums1[:], 而 [] 也代表一个新的 list 对象,我们需要用 nums1[:] = []。

解题思路(双指针从前往后)

一般来说,涉及到有序数组,可以想一想是不是可以使用双指针法来达到O(n+m)的时间复杂度。

最直接的算法实现是将指针p1置为nums1的开头, p2为nums2的开头,在每一步将最小值放入输出数组中。

由于 nums1 是用于输出的数组,需要将nums1中的前m个元素放在其他地方,也就需要 O(m)的空间复杂度。

db3e60864127083f50ac55dcec2a8728.png

class Solution(object):
    def merge(self, nums1, m, nums2, n):
        # 将nums1中的有效元素copy一份出来
        nums1_copy = nums1[:m]
        nums1[:] = []
        
        # 设置好指针
        p1, p2 = 0, 0
        # 比较nums1_copy和nums2指针所指向元素的大小,较小的重新写入nums1
        while p1 and p2             if nums1_copy[p1]                 nums1.append(nums1_copy[p1])
                p1 += 1
            else:
                nums1.append(nums2[p2])
                p2 += 1
        # 剩下元素的处理
        if p1             nums1[p1+p2:] = nums1_copy[p1:]
        if p2             nums1[p1+p2:] = nums2[p2:]

解题思路(双指针从后往前)

对于双指针从前往后比较,需要使用额外空间。如果我们从nums1的末尾开始,则不需要额外空间。这里我们再使用一个指针p来最终添加元素的位置。

c7d072aa1d88824cc1feee9c527e8524.png

class Solution(object):
    def merge(self, nums1, m, nums2, n):
        # 设置三个指针
        p1, p2, p = m-1, n-1, m+n-1
        while p1 >= 0 and p2 >= 0:
            if nums1[p1]                 nums1[p] = nums2[p2]
                p2 -= 1
            else:
                nums1[p] = nums1[p1]
                p1 -= 1
            p -= 1
        # 如果nums1都比完了,nums2剩下的元素(nums比完了,nums1前面的不用变)
        nums1[:p2 + 1] = nums2[:p2 + 1]
        
            
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值