刷题日记02
本题是排序类题目,难度为简单,复盘一下做题过程。
题目:给你两个按 非递减顺序 排列的整数数组 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 + nnums2.length == n0 <= m, n <= 2001 <= m + n <= 200-109<= nums1[i], nums2[j] <= 109
说实话理解这题的要求之后,我就有思路了,现将nums2和nums1合并,然后再排序,排序的方式刚好我刚学完,决定用快速排序。因此这题关键就在于如何将两个数组合并,合并的关键点就在于我要找到nums1正确的位置将nums2的值赋值过去。
看了示例后,这题我最开始的合并思路是这样想的:
三个示例代表了三种情况。第一个就是正常情况,因为nums1是升序排列,所以我要找到第一个为0的元素的索引,然后从这个索引开始把nums2的值对应存进去;第二个是nums2是空数组,长度为0,所以不用合并,对nums1排序即可;第三个是nums1自己的长度为0,nums2长度为1,这种情况直接将nums2[0]赋值给nums1[0]即可;
进行了以上分析,我就开始写合并程序了,一代合并程序如下:
//先把两个数组合并成一个
//定义一个指针,指向nums1第一个为0的元素
int index = 0;
//先要判断是否能合并,如果n==0,就没有合并的必要,对nums1进行排序就好
//如果n!=0,就把nums1的第一个为0的索引找到就行
if (n != 0){
while (nums1[index] != 0){
index++;
}
for (int i = 0; i < nums2.length; i++) {
nums1[index] = nums2[i];
index++;
}
写完之后我感觉我这可对了,老厉害了,在写完排序代码之后就兴奋的点了提交,果不其然,解答失败。当时我惊了,他的给输入nums1竟然是这样的[-1,0,0,3,3,3,0,0,0],还有负数的操作,然后我就知道是我想简单了,不能通过在第一个为0的元素位置就开始赋值。
偷摸看了眼题解,恍然大悟,是真的简单呀,于是就有了二代合并代码
for (int i = 0;i < n;i++){
nums1[i+m] = nums2[i];
}
能看出来真的简单,只要想明白了nums1的长度问题就行了。nums1总长度为m+n,m就是真实数值的长度,并且这m个数已经升序排列了,后面n个数都是0。那也就是说第m个元素开始不都是0吗,都应该被nums2赋值。这下合并过程就清晰了,后面的排序代码不就随便写了吗。
附上我的完整小趴菜代码
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
// //先把两个数组合并成一个
// //定义一个指针,指向nums1第一个为0的元素
// int index = 0;
// //先要判断是否能合并,如果n==0,就没有合并的必要,对nums1进行排序就好
// if (n != 0){
// while (nums1[index] != 0){
// index++;
// }
// for (int i = 0; i < nums2.length; i++) {
// nums1[index] = nums2[i];
// index++;
// }
// }
for (int i = 0;i < n;i++){
nums1[i+m] = nums2[i];
}
//合并之后进行排序[1,2,3,4,5,6]
sort(nums1);
}
//排序
public static void sort(int[] a){
int lo = 0;
int hi = a.length - 1;
sort(a,lo,hi);
}
public static void sort(int[] a,int lo,int hi){
if (lo >= hi){
return;
}
//获取分界值索引
int partition = partition(a, lo, hi);
sort(a,lo,partition - 1);
sort(a,partition + 1,hi);
}
public static int partition(int[] a,int lo,int hi){
//确定基准值
int key = a[lo];
int right = hi + 1;
int left = lo;
while (true){
//从右边开始找
while (less(key,a[--right])){
if(right == lo){
break;
}
}
//从左边开始找
while (less(a[++left],key)){
if (left == hi){
break;
}
}
//判断结束条件
if (left >= right){
break;
}else {
exch(a,left,right);
}
}
//交换基准值和right所在处的值
exch(a,lo,right);
return right;
}
//比较大小
public static boolean less(Integer v,Integer w){
return v.compareTo(w) < 0;
}
//交换
public static void exch(int[] a,int i,int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
这代码结果还挺厉害,我都没想到还能打败这老些人哈哈哈
查看23道真题和解析