本篇博客会讲解力扣“88. 合并两个有序数组”这道题,这是题目链接。
其实,有经验的朋友一看到这个题目的名字,应该就明白了,这玩意和归并排序脱不了干系。下面我们来审题:
输出示例如下:
以下是一些提示和进阶要求:
这道题的思路是经典的归并排序的思路,即每次取小的放到新数组中,那么新数组也是有序的。不过这么做有一个问题:需要开辟一个新的数组,空间消耗较大。所以稍微改进一下:每次取小的放到数组1中。但这样又有新的问题:会导致有效数据被覆盖,比如数组1的第一个数比数组2的第一个数大,一开始就会把数组1的第一个数给覆盖了。
既然以上思路不行,那就再改进一下:不是从前往后遍历,而是从后往前。换句话说,从后往前分别遍历2个数组,每次取大的数,放到数组1的后面就行了。这样无论如何都不会导致有效数据被覆盖。
下面动手写代码:
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
int end1 = m - 1; // 从后往前遍历数组1的有效数据
int end2 = n - 1; // 从后往前遍历数组2的有效数据
int end = m + n - 1; // 从后往前,寻找有效的目标位置
while (end1 >= 0 && end2 >= 0)
{
// 把大的数放到后面
if (nums1[end1] > nums2[end2])
{
nums1[end--] = nums1[end1--];
}
else
{
nums1[end--] = nums2[end2--];
}
}
}
当其中一个数组的有效数据全部遍历结束,此时有2种情况:
- 数组1遍历结束,此时有些有效数据还在数组2中,需要把这些数据拷贝到数组1中。
- 数组2遍历结束,此时数组1没有遍历完的有效数据本身就在数组1中,无需处理。
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
int end1 = m - 1; // 从后往前遍历数组1的有效数据
int end2 = n - 1; // 从后往前遍历数组2的有效数据
int end = m + n - 1; // 从后往前,寻找有效的目标位置
while (end1 >= 0 && end2 >= 0)
{
// 把大的数放到后面
if (nums1[end1] > nums2[end2])
{
nums1[end--] = nums1[end1--];
}
else
{
nums1[end--] = nums2[end2--];
}
}
// 判断数组2是否还有数据没有拷贝到数组1中
while (end2 >= 0)
{
nums1[end--] = nums2[end2--];
}
}
这就通过了,非常完美。
总结
- 归并排序的思路:取小的放前面,或者取大的放后面。
- 如果从前往后会覆盖,那就从后往前。
感谢大家的阅读!