数组算法题 - 合并两个有序数组
合并两个有序数组
88. 合并两个有序数组 - 力扣(LeetCode) 刷题时间:
- 25/12/23

我的解法
▼java复制代码class Solution { public void merge(int[] nums1, int m, int[] nums2, int n) { if (n == 0) return; for (int i = m, j = 0; i < m + n; i++) { nums1[i] = nums2[j]; j++; } for (int i = m + n - 1; i > 0; i--) { for (int j = 0; j < i; j++) { if (nums1[j] > nums1[j + 1]) { int temp = nums1[j]; nums1[j] = nums1[j + 1]; nums1[j + 1] = temp; } } } } }
优点
- 正确处理了
n==0的特殊情况 - 先合并再排序的思路
- 使用了经典的冒泡排序法 缺点
- 时间复杂度高
- 没有利用"有序"的条件
题解
- 方案一(额外空间合并):
- 时间复杂度是O($m+n$), 空间复杂度是O($m+n$)
- 设置额外数组存储结果,采用三指针,最后将结果复制到nums1中
▼java复制代码class Solution { public void merge(int[] nums1, int m, int[] nums2, int n) { int[] merged = new int[m + n]; int i = 0, j = 0, k = 0; // 双指针合并 while (i < m && j < n) { if (nums1[i] <= nums2[j]) { merged[k++] = nums1[i++]; } else { merged[k++] = nums2[j++]; } } // 处理剩余元素 while (i < m) merged[k++] = nums1[i++]; while (j < n) merged[k++] = nums2[j++]; // 复制回nums1 System.arraycopy(merged, 0, nums1, 0, m + n); } }
- 方案二(原地合并):
- 时间复杂度是O($m+n$), 空间复杂度是O(1)
- 与方案一的区别是, 直接在nums1数组上进行操作, 空间复杂度直接降为O(1)
▼java复制代码class Solution { public void merge(int[] nums1, int m, int[] nums2, int n) { if (n == 0) return; int i = m - 1; int j = n - 1; int k = m + n - 1; while (i >= 0 && j >= 0) { if (nums1[i] > nums2[j]) { nums1[k--] = nums1[i--]; } else { nums1[k--] = nums2[j--]; } } // 运行到这里, 两者必有一个小于0 // 如果是j用完了(nums2),那么程序就可以结束了 // 如果是i先用完了(nums1),那么就把nums2剩余的元素排进去即可 while(j >= 0){ nums1[k--] = nums2[j--]; } } }
- 思路
- 我的解法使用的是冒泡排序法, 先合并数组, 再使用冒泡排序法进行排序
- 时间复杂度是O($(m+n)^2$), 空间复杂度是O(1)
- 可以考虑降低为O($m+n$)
- 充分利用已知条件: 两个数组都是"有序"的, 可以使用"归并排序"的合并思想
- 使用三个指针
- 一个指针
i指向nums1的最后有效索引(m-1), 一个指针j指向nums2的最后有效索引(n-1),一个指针k指向nums1的最后索引(m+n-1)
- 一个指针
- 比较
nums1[i],nums2[j]的大小,较大者排到nums1的最末尾(nums1[k]).- 直到其中一个数组被比较排序完, 这里有一个边界点:
- 就是如果nums2数组先排序完,那么程序可以直接结束了, 因为nums1数组剩余的元素肯定是有序的,且位置正确.
- 直到其中一个数组被比较排序完, 这里有一个边界点:
- 使用三个指针
- 我的解法使用的是冒泡排序法, 先合并数组, 再使用冒泡排序法进行排序

- 如果nums1数组先排序完, 那么可以直接把nums2数组剩余的元素逐个排进nums1即可
2. 算法思想
- 归并排序(有序数据)
- 两个有序数组进行排序, 那么可以使用归并排序的合并思想
- 时间复杂度的优化
- 冒泡排序法的O($n^2$)时间复杂度, 必然是要被优化的, 需要优化为$O(n)$.
- 时间复杂度的优化

- 双指针/三指针的应用(合并有序数组/链表)
- 指针负责元素的选取, 进行比较
-
nums1[i]>nums2[j]-> 取nums1[i], i-- - 否则 -> 取nums2[j], j-- - 每次k--- 从后往前操作 - 原地操作
- 这决定了是采用额外数组存储,还是原地操作
- 如果需要"原地"修改数组, 且可能会覆盖未处理数据时,就不能使用从前往后.
- 而是从后往前
- 从后往前操作 - 原地操作
- 题目变式 - 思考
- 如果题目要求改为输出结果为降序呢?
- 两个升序的数组,输出nums1为降序
- 如果采用原地排序的办法
- 从前往后: 会直接覆盖未处理的元素(
nums1[0]), 不管索引从哪里开始 - 从后往前: 也可能会覆盖元素, 例如:
- 从前往后: 会直接覆盖未处理的元素(

- 如果采用额外空间的方法
- 这道题就很简单了
- 同样设置两个指针指向两个数组(从0索引开始), 比较大小, 较小者放在额外数组的末尾. 逐个比较存储即可.
| 场景 | 最佳解法 | 时间复杂度 | 空间复杂度 | 关键点 |
|---|---|---|---|---|
| 升序(原题) | 从后往前原地合并 | O(m+n) | O(1) | 利用nums1后面的空位 |
| 降序 | 额外空间合并 | O(m+n) | O(m+n) | 避免覆盖问题 |
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
作者分享
Day 7
✅ 今天做了:云图库项目的 5-用户传图
1.通过URL传图 2.批量抓取和上传图片
⏰ 明天计划:最少把6-图片优化给做完!
📚 今日感悟:
做项目,真的耗时间,并不是将代码简单复制粘贴那么简单,还需要理解代码,运行跑起来调试,这些花的时间才是主要的!
3
字符串算法题 - 字符串相加
3
Day 6
✅ 今天做了:一道算法题(买卖股票的最佳时机), 一道八股(面向对象的三大特征)
『 数组算法 - 买卖股票的最佳时机 』💎 https://www.codefather.cn/post/2004184783197937665
⏰ 明天计划:一道算法,一道八股,项目
📚 今日感悟:算法还是先用暴力解法, 后面看题解是运用了贪心思想的一次遍历.
面向对象的三大特征, 封装是基础, 继承实现了代码的复用和扩展, 多态通过方法重载和方法重写实现了"同一接口,多种实现"的功能
4
数组算法 - 买卖股票的最佳时机
4
Day 5
✅ 今天做了:写了两道八股题, 健身练了肩
⏰ 明天计划:项目, 两道算法, 一道八股
📚 今日感悟:效率好低啊, 早上学了, 下午健身,晚上有事. 效率真的太低了, 也就非健身日学习时间能长一点.
4
