领扣网算法学习笔记
本系列的算法题目来自领扣网
数组类算法第七天
题目:88. 合并两个有序数组
给定两个有序整数数组 *nums1 *和 nums2,将 *nums2 *合并到 *nums1 中,*使得 *num1 *成为一个有序数组。。
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
说明:
- 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
- 你可以假设 *nums1 *有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
解题过程:
思路一:
看到题的第一个想法是将数据插入然后,数据往后移,但是移动数据的代价太大,之后想的是数组长度够了,直接从后面放就好了。
代码如下:
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
// 反向思维,从前面插入的话移动数据的代价太大,但是从后面排的话就不存在
if((nums1.length == 1) && (nums1[0] == 0)){ // 去除nums1没有数据的情况
nums1[0] = nums2[0];
return;
}
int keynum = m+n-1; // 记录数据保存的最后一个位置
int arr1 = m-1;
for(int i = n-1;i>=0;i--){
for(;arr1>=0;arr1--){
if(nums2[i] >= nums1[arr1]){
nums1[keynum] = nums2[i];
keynum--;
break;
}else{
nums1[keynum] = nums1[arr1];
keynum--;
}
}
if(arr1<0){ // 如果nums1第一个值大于nums2里的值,会导致循环完后nums2的值没有插入完
nums1[keynum] = nums2[i]; // 此时数据都是小的,直接往前插入即可
keynum--;
}
}
}
}
// 5ms
后续思考:
其实写完一想,我觉得没必要写成嵌套循环,毕竟循环次数我是知道的,于是有了思路二。
思路二:
循环次数 = m + n 次,直接写一个这样的循环就可以了。
代码如下:
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
// 反向思维,从前面插入的话移动数据的代价太大,但是从后面排的话就不存在
if((nums1.length == 1) && (nums1[0] == 0)){
nums1[0] = nums2[0];
return;
}
int k = m+n-1;
for(;k>=0;k--){
if(m!=0 && n!=0){
if(nums1[m-1] < nums2[n-1]){
nums1[k] = nums2[n-1];
n--;
}else{
nums1[k] = nums1[m-1];
m--;
}
}else if(m==0){
nums1[k] = nums2[n-1];
n--;
}else if(n == 0){
nums1[k] = nums1[m-1];
m--;
}
}
}
}
//3ms
后续思考:
这个主要要注意几个特殊的情况,
1. 第一个就是第一个数组直接没有值,第二个数组可能有且只有一个值,这种情况直接将第二个数组的值赋给第一个数组即可,
2. 第一个数组的最小值比第二个数组的部分值或者全部值都大的时候,注意判断不要越界和注意要添加完第二个数组的值;
3. 第二个数组的最小值比第一个数组的部分值或者全部值都大的时候,注意不要越界。
4. 我发现这 2、3 两种情况不是特殊情况,是肯定会出现的。
领扣上面该题其他高质量范例:
class Solution {
public static void merge(int[] nums1, int m, int[] nums2, int n) {
//边界:
if(n==0) {
return;
}
int i = 0,j=0;
while(i<m) {
if(nums1[i]<=nums2[j]) {
i++;
}else {
swap(nums1,i++,nums2,j);
//调整顺序
while(j+1<n&&nums2[j]>nums2[j+1]) {
swap(nums2, j,(j+1));
j++;
}
j = 0;
}
}
while(j<nums2.length) {
nums1[i++] = nums2[j++];
}
}
private static void swap(int[] nums2, int i, int j) {
// TODO Auto-generated method stub
nums2[i] = nums2[i]^nums2[j];
nums2[j] = nums2[i]^nums2[j];
nums2[i] = nums2[i]^nums2[j];
}
private static void swap(int[] nums1, int i, int[] nums2, int j) {
int temp = nums1[i];
nums1[i] = nums2[j];
nums2[j] = temp;
}
}
// 4ms
自我整理:
这里的思路就是先将最大值放到数组二中,然后将数组二的值放到数组后面去。
这部分我没有这样想过,我做这题的时候只想着把数插进去,没有想到先排序然后在插入。
方法很多,需要多个方位的思考。