[LeetCode][C++] 合并两个有序数组

合并两个有序数组

给你两个有序整数数组 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]


思路:

  1. 特殊情况,num1序列为空,此时直接将num2赋值给num1。
  2. 通常情况,遍历num2序列,将其中的元素一个个插入到num1。
    \quad- 先和num1的最后一个元素比较,判断是否在num1末尾插入。
    \quad- 和其他元素比较,找到插入位置,并记录插入位置
  3. 由于该题的数据格式原因,我们每次插入一个元素到num1,要更新num1中的有效元素个数,即m++,不能直接调用num1.size()。最后,我们需要删除num1末尾的0。

代码:
需要注意vector的insert()方法:

//在位置为m的元素前插入元素to_insert
//插入后,m的位置存储元素to_insert 
vector<int> nums;
nums.insert(nums.begin()+m,to_insert);  

函数整体代码如下:
方法一:从后面开始插入

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int l=m-1,r=n-1, to_insert=m+n-1;
        while(l>=0 && r>=0)
        {
            if(nums1[l]>=nums2[r])
            {
                nums1[to_insert--]=nums1[l--]; 
            }else{
                nums1[to_insert--]=nums2[r--]; 
            }
        }
        while(l>=0)
                nums1[to_insert--]=nums1[l--];
        while(r>=0)
                nums1[to_insert--]=nums2[r--];
        
    }
};

麻烦的方法二:

void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int cur_ind=0, j=0;
        //nums1为空
        if(m==0)
        {
            nums1=nums2;
        }else
        { //通常情况            
            for(int i=0;i<n;i++)   
            {
                int to_insert=nums2[i];
                //先和最后一个元素比较
                if(to_insert>=nums1[m-1])   
                {
                    nums1.insert(nums1.begin()+m,to_insert);   //末尾插入元素
                    m++;     //更新nums1元素个数
                    continue;
                }
                //和其他元素比较,找到插入位置
                for(j=cur_ind;j<m-1;j++)  
                {
                    int to_compare_left=nums1[j];
                    int to_compare_right=nums1[j+1];
                    if(to_insert >= to_compare_left && to_insert < to_compare_right )
                    {
                        cur_ind=j+1;
                    }
                }
                //插入
                nums1.insert(nums1.begin()+cur_ind,to_insert);  //在cur_ind前插入元素,插入后,cur_ind指向插入元素     
                m++;   //更新nums1元素个数
            }
            //删除nums1结尾的0
            for(int i=0;i<n;i++)
            {
                nums1.erase(nums1.end()-1);
            }
        }       
    }

简化代码:

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
		if (m == 0)
    	{
        	nums1 = nums2;
        	return ;
    	}
		
		int cur = 0;
		for (int i = 0; i < n; i++)
			nums1.pop_back();
		for (int i = 0; i < n; i++)
		{
			if (nums2[i] >= nums1[m - 1])
			{
				for (int j = i; j < n; j++)
				{
					nums1.push_back(nums2[j]);
					m++;
				}
				break;
			}
			while (nums2[i] >= nums1[cur])
			{
				cur++;
			}
			nums1.insert(nums1.begin() + cur, nums2[i]);
			cur++;
			m++;
		}
	}
};

结果:
合并两个有序数组

<think>好的,我需要解决用户在LeetCode合并两个有序数组的问题,提供C++的解决方案,包括测试用的main函数。首先,我需要回顾一下合并两个有序数组的常见方法。 根据用户提供的引用,特别是引用[4]和[5],合并两个有序数组的一种高效方法是从后往前填充数组,这样可以避免从前往后合并时可能出现的元素覆盖问题。因为题目中提到数组A有足够的空间容纳B的元素,所以不需要额外申请空间,这样可以达到O(m+n)的时间复杂度和O(1)的空间复杂度。 接下来,我需要将这个方法转化为C++代码。根据引用[4]中的Java示例,我们可以调整指针的起始位置。例如,使用三个指针:ia指向A的最后一个有效元素,ib指向B的最后一个元素,icur指向合并后的数组末尾。然后比较A[ia]和B[ib],将较大的元素放入icur位置,向前移动相应的指针。如果B中还有剩余元素,继续填充到A的前面。 同时,要注意C++数组的索引是从0开始的,所以初始化ia为m-1,ib为n-1,icur为m+n-1。循环条件应该是ia >=0 && ib >=0,处理完较大的元素后,处理剩余的B元素。 然后,关于测试的main函数部分,需要创建A数组时预留足够的空间,比如使用vector<int> A(m + n)或者动态数组。初始化A的前m个元素为有序,B的n个元素也为有序。调用merge函数后,输出合并后的数组。 需要检查代码是否符合LeetCode的要求,例如函数签名为void merge(vector<int>& nums1, int m, vector<int>& nums2, int n)。同时,测试用例要覆盖A和B的各种情况,比如A为空,B为空,或者元素交错的情况。 最后,确保代码中没有语法错误,比如正确的循环结构,指针移动,以及向量的正确使用。测试main函数应该能够正确运行输出结果。</think>### C++实现合并两个有序数组LeetCode解决方案 #### 解决方案说明 题目要求将两个已排序数组合并到第一个数组中,且第一个数组有足够的空间容纳所有元素。最优解法采用**逆向双指针法**,时间复杂度$O(m+n)$,空间复杂度$O(1)$。关键点是从两个数组的末尾开始比较,避免正向合并时的元素覆盖问题[^4][^5]。 #### 完整代码实现 ```cpp #include <vector> #include <iostream> using namespace std; class Solution { public: void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) { int i = m - 1; // nums1有效元素末尾 int j = n - 1; // nums2末尾 int k = m + n - 1; // 合并数组末尾 // 逆向比较填充 while (i >= 0 && j >= 0) { nums1[k--] = (nums1[i] > nums2[j]) ? nums1[i--] : nums2[j--]; } // 处理nums2剩余元素 while (j >= 0) { nums1[k--] = nums2[j--]; } } }; // 测试用例 int main() { vector<int> A = {1,3,5,0,0,0}; // 初始化预留空间 vector<int> B = {2,4,6}; Solution().merge(A, 3, B, 3); cout << "合并数组: "; for (int num : A) { cout << num << " "; } return 0; } ``` **输出结果**: `合并数组: 1 2 3 4 5 6` #### 代码解析 1. **逆向指针初始化**:`i`指向nums1最后一个有效元素,`j`指向nums2末尾,`k`指向合并后的末尾位置。 2. **核心循环**:比较两数组当前最大值,选择较大的放入`nums1[k]`,移动对应指针。 3. **剩余元素处理**:若nums2仍有元素未合并,直接填充到nums1前端。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值