今天的这道leetcode题,将通过逆向双指针来进行解决。
涉及知识:
数组相关知识的基础;
目录
一、题目描述
二、思路分析
1、题目思路
2、代码分析
三、代码提交
题目名称:合并两个有序数组(编号88)
难度:简单
简单来说,该题就是给了两个有序的数组nums1和nums2,然后将两个数组合并后存储在nums1里。
通过该题描述,合并后的数组是有序的。
这时有些聪明的人,也许就会想到把两个数组合并后再直接用库方法sort()来排序。
虽然可以直接解出该题,但不建议这么做。
这么做的话,这道题就没有意思了呀。
(1)该题中给的参数不止有两个数组,还有对应两个数组的长度(m和n)。那么我们可以通过该长度来获取数组的下标。
(2)定义两个数组的最后一个元素的下标位置,然后通过遍历,从每一个数组的最后一个下标位置开始进行比较。(从后面开始确定)
(3)由于两个数组合并后要存储在第一个数组nums1里面,那么我们何不将比较好后较大的一个元素,直接存储在nums1的最后一个下标位置(nums1的长度得进行扩容)。
(4)那么我们就需要有三个位置的指针,分别是第一个数组nums1的m-1位置,第二数组nums2的n-1位置和要增添进第一个数组nums1末尾的m+n-1位置。
- 为什么都要减1?
因为数组是从下标0位置开始,m和n,m+n都是作为数组的长度,需要减1才能获取最后一个下标位置。
- m+n是代表什么?
因为要合并两个数组,并存储进第一个数组里面,那么存储后的第一个数组nums1,其长度不得变成两个数组长度之和(m+n)。
代码示例:
public class TestDemo1 {
public static void merge(int[] nums1, int m, int[] nums2, int n){
int i=m-1; //nums1数组的末位置
int j=n-1; //nums2数组的末位置
int k=m+n-1; //合并后nums1数组的末尾置
while(i>=0&&j>=0){
//从末尾开始比较,直到其中一个数组下标位置为0
if(nums1[i]>=nums2[j]){
//如果数组1的i位置元素大于或等于数组2的j位置元素,就将大的一方存储在k的位置
nums1[k]=nums1[i];
i--; //之后要将i和k向左移动
k--;
} else{
//如果数组2的j位置元素大于或等于数组1的i位置元素,就将大的一方存储在k的位置
nums1[k]=nums2[j];
j--; //之后要将j和k向左移动
k--;
}
}
//当然有可能存在其中一个数组的长度小于另外一个
//这时就会出现其中一个数组已经遍历完,但另外一个数组却没有
//那么我们就要将还没遍历完的数组直接存储在k的下一个位置里,直到这个数组也遍历完
while(i>=0){
nums1[k]=nums1[i];
i--;
k--;
}
while(j>=0){
nums1[k]=nums2[j];
j--;
k--;
}
//一切遍历完后,就完成了合并的过程
}
public static void main(String[] args) {
//假设两个数组的长度都是3
int []arr1={1,2,3,0,0,0};
int []arr2={4,5,6};
int m=3,n=3;
merge(arr1,m,arr2,n); //调用合并方法
System.out.println(Arrays.toString(arr1)); //将数组转换成字符串再打印出来
}
}
(1)这道题利用逆向双指针来解决,那么此处我们得定义三个位置的指针。
(2)为了对这两个数组中的每一个元素进行比较 ,因为是从末位置开始往前循环比较,那么当定义的数组长度i或j小于0时,即说明这个数组已经都存储进nums1里了。
以下面这个图为例,比较完后,j小于0,nums2里的4、5、6都存进绿色方框位置,此时合并有序数组就完成了。
(3)
可有一种情况是,如果其中一个数组的长度小于另外一个数组长度,那么就会出现长度小的数组已经存进去了,但大的数组还没进行排序存进去。
还有一种情况是nums2的数组元素都小于nums1的数组元素,那么当nums1遍历完后循环结束,nums2的元素还没存进nums1里去.
因此我们得对这两种情况进行处理。
对两个数组进行一次遍历判断。
如果下标位置还是大于或等于0,说明还没有完全存储进数组1,那么只需继续存进对应nums1的k位置,再更新k和对应数组的下标i或j即可。
【注意】:
这种方法只能应用于两个“有序”数组 ,前提条件是有序,如果是两个非有序数组,是不可以用以上这种方法进行合并的.