1、将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
这个题目本来想着重新设置一个链表然后挨个对比两个链表的元素大小完成。但是要求了在两个链表基础上组成,所以这种方法就不可行。因此可以选择用递归的方法,在原有基础上完成。
代码:
(1)递归
/**
* 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* mergeTwoLists(ListNode* list1,ListNode* list2) { //设置mergeTwoLists,进行下一步递归
if(list1==nullptr){
return list2;
}else if(list2 ==nullptr){
return list1;
}else if(list1->val < list2 ->val){ //在list上进行递归
list1->next = mergeTwoLists(list1->next,list2);
return list1;
}else{
list2->next = mergeTwoLists(list1,list2->next);
return list2;
}
}
};
这个由于是利用递归,时间复杂度为O(n+m),即两个数组的元素数量,空间复杂度O(m+n),没有耗费多余空间,但在递归调用函数的时候用到了多余的栈空间(递归需要叠加栈)。
(2)迭代:即利用一个新开辟的头节点和指针来找出顺序值。
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1,ListNode* list2) {
ListNode*prehead = new ListNode(-1);
ListNode*prev = prehead;
while(list1 !=nullptr && list2!=nullptr){
if(list1->val < list2->val){
prev->next = list1; //prev指针指向下一个list1,因为list1较小
list1 = list1->next; //list1的指针在顺序链表上位移
}else{
prev->next = list2;
list2 = list2->next;
}
prev = prev->next; //移动prev指针
}
prev->next =list1== nullptr? list2:list1; //这一句不是太理解
return prehead->next; //输出prehead之后的链表
}
};
主要就是最后依据把没有加入的链表元素加入的操作有点不懂,大概时间复杂度野味O(m+n),需要遍历。空间复杂度为O(1),没有使用多余空间。
2、给你单链表的头节点
head
,请你反转链表,并返回反转后的链表。示例:输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
这个是一个典型的链表题,可以多设置几个节点进行数值存储然后利用指针来得到反转的链表。
(1)迭代:这里之所以输出prev是因为有判定条件cur,这时候cur应当为空,所以输出prev。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode*prev = nullptr;
ListNode*cur = head;
while(cur){
ListNode*next = cur->next; //设置一个next存储cur下一个节点的数值
cur->next = prev; //cur指向prev
prev = cur; //prev节点的数值等于cur
cur = next; //cur的数值等于next
}
return prev;
}
};
时间复杂度O(m),空间复杂度为O(1)。
(2)递归
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if( !head||!head->next){ //这一步代表head已经到了头,或者本身就一个节点,可以输出了
return head;
}
ListNode*ans =reverseList(head->next);
head->next->next = head; //构建反向指针
head->next = nullptr; //释放原有方向指针
return ans;
}
};
引用本身实现递归,时间复杂度O(m),由于递归调用栈空间,所以空间复杂度为O(m)。