一、解题过程
leetcode88.合并两个有序数组
(1)题目描述
题目链接如下:
leetcode88.合并两个有序数组https://leetcode.cn/problems/merge-sorted-array/
给你两个按 非递减顺序 排列的整数数组 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 中的元素。
示例 1:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。
提示:
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-10^9 <= nums1[i], nums2[j] <= 10^9
做题分析:
这题题意比较清晰易懂,故
用自己的话解释题意:
给定两个非递减数组,将两个数组按照非递减顺序排列合并到第一个数组中。第一个数组长度为两数组元素个数和。
开始思考解决方法:
其实我们可以发现这题比较简单,经典的一个双指针算法题目。
最开始的想法:我们只要用到l,r两个指针,然后l,r指向每个数组的最小的元素进行比较,
因为小的要放在前面,但我们最后数值要求放在的是第一个数组,所以,我们可以考虑引用一个新的数组mm,先把正确答案放在新数组mm中,最后把mm的数值复制到第一个数组里。
好的,这就是大概的想法。代码实现:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i=0,j=0,z=0;
int mm[500];
while(z<m+n){
if((i<m&&j<n)){
if(nums1[i]>nums2[j]){
mm[z]=nums2[j];
j++;
z++;
}
else {
mm[z]=nums1[i];
i++;
z++;
}
}
else if(i<m){
mm[z]=nums1[i];
i++;
z++;
}
else {
mm[z]=nums2[j];
j++;
z++;
}
}
for(int k=0;k<m+n;k++){
nums1[k]=mm[k];
}
}
};
BUT
有个很细节的东西,我们可以发现,其实第一个数组里早就开辟好了足够的空间,那么等于说我们后面的空间完全是闲置的。
从这一方面下手的话,我们发现,可以尝试倒着比较数组的元素,直接一步到位放到第一个数组中,
这样相比较起来我们就少了一个数组的定义,可以有效减少空间复杂度。
这时候我们用三个指针:
l代表原本的第一个数组所指元素指针。
r代表原本的第二个数组所指元素指针。
i代表我们现在处理到了第一个数组的i位置(此时(i,nums1_len+nums2_len]该区间是已处理好的区间)
代码如下:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = nums1.size() - 1;
l=m-1;
r=n-1;
while (r >= 0) {
while (l>=0&&nums1[l]>nums2[r]) {
swap(nums1[i--], nums1[l--]);
}
swap(nums1[i--],nums2[r--]);
}
}
好的,那这一题,完美结束!
leetcode206.反转链表
(1)题目描述
题目链接如下:
力扣206.反转链表https://leetcode.cn/problems/reverse-linked-list/description/
给你单链表的头节点head,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
提示:
-
链表中节点的数目范围是 [0, 5000]
-
-5000 <= Node.val <= 5000
做题分析:
这题题意依旧清晰易懂,故
用自己的话解释题意:
把一个链表,反着读一遍,返回头指针;
开始思考解决方法:
链表的题,其实最重要的就是头结点的处理和中间的连接细节。
我们先转化为数组问题,如果是数组的话,我们怎么反转?
倒着扫一遍……
那转化为链表,根据链表的特性,我们最后知道的只有头部节点
那么,我们是不是可以,选择把最后一个元素作为头节点,把第一个元素给指向空值。
ok
按照这个思路的话,我们接下来只需要把每各元素之间的连接顺序倒换一下就好了
这是针对于每两个链表元素之间,交换一下顺序即可。
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* l=NULL,*r=head,*t;
while(r!=NULL){
t=r->next;
r->next=l;
l=r;
r=t;
}
return l;
}
};
完美结束!
二、总结及计划
今天是第二天练习,题目类别是双指针与链表的基础应用。