做题总结 Leetcode 88. 合并两个有序数组

本文讲述了在解决LeetCode88合并两个有序数组问题时,从初始直接填充、使用sort函数到优化vector操作的逐步改进过程,包括空间复杂度的优化和避免堆缓冲区溢出的错误分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

做题总结 Leetcode 88. 合并两个有序数组

思考一

将nums2直接填入nums1最后(以官方示例1为例,nums1最终为1 2 3 2 5 6) ,然后使用sort函数 nums1.sort();即可解题。
注意sort函数时间复杂度O(nlogn)

思考二

设置一个vector nums3,分别比较nums1和nums2中元素的大小,按照非递减顺序存入nums3,最后将nums3赋值给nums1(nums1 = nums3;) 空间复杂度O(m+n)。

1、首次书写为:
class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        vector<int> nums3;
        int i,j;
        for(i=0,j=0; i<m || j<n;) {
            if(nums1[i] <= nums2[j]) {
                nums3.push_back(nums1[i]);
                i++;
            } else {
                nums3.push_back(nums2[j]);
                j++;
            }
        }
        nums1 = nums3;
    }
};

报错如下图所示:
在这里插入图片描述
错误分析:
(1)会把nums1中用来占位的0全部赋给nums3(0是用来占位的,不计入nums1数组中):会进入第7行,直到把nums1的数字全部计入nums3。
(2)AddressSanitizer: heap-buffer-overflow on address
意思是在地址上发生了堆缓冲区溢出。这通常是由于程序试图访问超出分配给它的内存范围的数据而导致的。这可能会导致程序崩溃或产生不可预测的行为。
详见:https://wenku.youkuaiyun.com/answer/be06c5686f13d2ec389b7ab083a9f098
分析:接(1)的错误,当循环进行到i=m-1时,nums1[i](也就是0)赋给nums3,此时i++ = m。下一次循环,在第七行 试图访问了nums[m],报错。

2、第一次修改

在第七行添加了 i<m 这个条件,保证nums1中的0不会被计入。

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        vector<int> nums3;
        int i,j;
        for(i=0,j=0; i<m || j<n;) {
            if(i<m && nums1[i] <= nums2[j]) {
                nums3.push_back(nums1[i]);
                i++;
            } else {
                nums3.push_back(nums2[j]);
                j++;
            }
        }
        nums1 = nums3;
    }
};

但是报错:Char 9: runtime error: reference binding to null pointer of type ‘int’
在这里插入图片描述

错误分析:这个错误的发生是因为当nums2为空的时候,第七行nums2[j]仍然让程序访问了nums2的下标。

3、第二次修改

在第四行插入对 nums2 的判断,如果nums2为空,答案就是最初的nums1。

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        if(n == 0) return;
        vector<int> nums3;
        int i,j;
        for(i=0,j=0; i<m || j<n;) {
            if(i<m && nums1[i] <= nums2[j]) {
                nums3.push_back(nums1[i]);
                i++;
            } else {
                nums3.push_back(nums2[j]);
                j++;
            }
        }
        nums1 = nums3;
    }
};

依旧报错: AddressSanitizer: heap-buffer-overflow on address
在这里插入图片描述

错误分析:
(1)最大值在nums1,假设nums1={1,2,5},nums2={4}。当nums3.push_back(nums2[0])之后,j++ = 1;(此时i=3),接着下一个循环进入语句if(i<m && nums1[i] <= nums2[j]) ,此时访问了nums2[1],数组访问越界。
(2)最大值在nums2,假设nums1={1,2,5},nums2={7}。当nums3.push_back(nums1[2])之后,i++=3;(此时j=0),接着下一个循环,在第七行只会到i<m的判断,因为是与运算,所以会直接进入else语句。
— i<m这个条件,保证了访问nums1不会越界
(3)最大值同时在nums1 nums2,因为第七行的<=,会先处理nums1,接下来情况与上述(2)相同。

4、第三次修改
class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        if(n == 0) return;
        vector<int> nums3;
        int i,j;
        for(i=0,j=0; i<m || j<n;) {
            if(j==n || i<m && nums1[i] <= nums2[j]) {
                nums3.push_back(nums1[i]);
                i++;
            } else {
                nums3.push_back(nums2[j]);
                j++;
            }
        }
        nums1 = nums3;
    }
};

运行成功。
在这里插入图片描述

思考三

做题时想到了题目移动零的解法,但是考虑到数据会被覆盖,就放弃了。看了评论题解后,发现其实可以从nums1的最末往前合并。

一些要注意的点

(1)vector初始化

    vector<int>nums3 = {1,2,3};
    vector<int>nums3(nums1.size(),0)

(2)如果像下面这么定义 ,就不可以使用push_back()。

    vector<int> nums3(m+n,0);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值