题目要求
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
示例 2:输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。
示例 3:输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。
提示:
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-109 <= nums1[i], nums2[j] <= 109
题目要求合并两个有序数组,其实一开始的想法我是想让他们都从左往右开始合并,然后创建一个额外的m+n大小的数组空间,这个想法有点类似于归并排序中对两个有序数组的合并,两个"指针"分别指向两个数组的开头,通过对两个指针当前数字大小的比较,然后将元素从小到大排序到新的数组里面。但是这样的空间复杂度就是O(m+n)。所以我有另一种想法就是将第一个数组指针上的元素和第二个数组指针对应的元素比较,如果第一指针1指向的元素小那么就指针1++,如果第二个指针指向的元素小,那么就将指针2指向的元素和指针1的元素互换,然后继续执行循环,left再++,但是像这样的话又考虑不了交换的nums1原来的元素和nums2后面的元素大小,放置的位置又有问题,且right指针在这个过程中一直不变,导致有很多细节上的问题出现。
最后考虑到nums1后面的元素都是空置的位置,可以利用该处空闲的位置来对数组进行排序,即将数组从小到大来进行排序,从而使得空置的位置得到利用。且当所有元素都排序完成的时候,当nums2数组的元素还没有完成排序的时候需要将nums2的元素从right处完全复制到nums1的位置上,因为此时nums1的所有元素已经排好序了,剩下的位置不用管,直接全部排nums2就行。有些注释代码是个人思路,可以忽略
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n)
{
首先对两个数组的大小进行判断,如果有的没有元素,那么就直接将有元素的数组完全复制到nums1上
if(m<=0|| n<=0)
{
nums1 = m?nums1:nums2;
}
int left = m-1, right = n-1, piv = m+n-1;
// int len1 = nums1.size(), len2 = nums2.size();
while(left>=0 && right>=0)
{
if(nums1[left] > nums2[right])
{
nums1[piv] = nums1[left];
// nums1[left] = 0;
piv--;
left--;
}
else
{
nums1[piv] = nums2[right];
piv--;
right--;
}
}
//判断nums2是否完全复制到该数组上,如果没有复制完,需要再进行额外的复制
//不存在nums1需要复制的情况,因为nums1就在本数组上,如果nums2数组已经复制完了,那么nums1数组一定会呆在原来的位置上
while(right >= 0)
{
nums1[right] = nums2[right];
right--;
}
// if(m<=0|| n<=0)
// {
// nums1 = m?nums1:nums2;
// }
// int left = 0, right = 0, piv = m+n-1;
// // int len1 = nums1.size(), len2 = nums2.size();
// while(left<m+n-1 && right<n)
// {
// if(nums1[left] <= nums2[right])
// {
// left++;
// }
// else
// {
// int tmp = nums2[right];
// nums[right] = nums1[left];
// nums1[left] = tmp;
// left++;
// }
// }
// //判断nums2是否完全复制到该数组上,如果没有复制完,需要再进行额外的复制
// //不存在nums1需要复制的情况,因为nums1就在本数组上,如果nums2数组已经复制完了,那么nums1数组一定会呆在原来的位置上
// while(right >= 0)
// {
// nums1[right] = nums2[right];
// right--;
// }
}
// int i = 0, j = 0;
// while(j<n && i<m+n)
// {
// if(nums1[i] <= nums2[j])
// {
// ++i;
// }
// else
// {
// int num = nums2[j];
// for(int k = i;k<m;++k)
// {
// nums1[k+1] = nums1[k];
// }
// nums1[i] = num;
// j++;
// i++;
// }
// }
// for(;j<n;++j)
// {
// n
// }
/*
//调用临时数组,时间复杂度为m+n,空间复杂度也为m+n
vector<int> nums(m+n);
int i = 0, j = 0, k = 0;
while(i<m && j<n)
{
if(nums1[i] <= nums2[j])
{
nums[k++] = nums1[i++];
}
else
{
nums[k++] = nums2[j++];
}
}
for(;j<n;j++)
{
nums[k++] = nums2[j];
}
for(;i<m;i++)
{
nums[k++] = nums1[i];
}
for(int x = 0;x<m+n;x++)
{
nums1[x] = nums[x];
}
*/
/*//时间复杂度较高
int i = 0;
for(int j = m;j<m+n;j++,i++)
{
nums1[j] = nums2[i];
}
sort(nums1.begin(), nums1.end());
}
*/
//需要从后往前循环,先将大的值判断,充分利用后面没用的空间
// int i = 0, j = 0;
// while(i<m+n && j<n)
// {
// }
};
以上代码思路仅个人想法,如有指正或者更好的想法,欢迎交流指正,谢谢大家