将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
真题点击此处:21. 合并两个有序链表
解题思路:
假设有两个有序链表 list1 和 list2,我们需要将它们合并为一个新的有序链表。
具体解题思路可以总结为以下几点:
这种方法利用了递归的特性,每次都选择较小节点进行合并,直到一个链表为空,然后将另一个非空链表直接连接到已合并的链表的末尾。
以下为代码实现:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if(list1 == nullptr){
return list2;
}else if(list2 == nullptr){
return list1;
}else if(list1->val < list2->val){
list1->next = mergeTwoLists(list1->next, list2);
return list1;
}else{
list2->next = mergeTwoLists(list1, list2->next);
return list2;
}
}
};
时间复杂度:O(n+m),其中 n 和 m 分别为两个链表的长度。因为每次调用递归都会去掉 list1 或者 list2 的头节点(直到至少有一个链表为空),函数 mergeTwoList 至多只会递归调用每个节点一次。因此,时间复杂度取决于合并后的链表长度,即 O(n+m)。
空间复杂度:O(n+m),其中 n 和 m 分别为两个链表的长度。递归调用mergeTwoLists 函数时需要消耗栈空间,栈空间的大小取决于递归调用的深度。结束递归调用时 mergeTwoLists 函数最多调用 n+m 次,因此空间复杂度为O(n+m)。
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
真题点击此处:206. 反转链表
解题思路:
假设有一个单向链表,我们需要将其翻转。例如,原始链表为 1->2->3->4->5,翻转后的链表为 5->4->3->2->1。
具体解题思路可以总结为以下几点:
这种方法利用了迭代的特性,每次将当前节点的下一个节点保存起来,然后将当前节点的 next 指针指向前面已经翻转好的链表,最后将 prev 和 curr 指针向后移动,直到遍历完整个链表。
以下为具体的代码实现:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while(curr != nullptr){
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
};
时间复杂度:O(n),其中 nnn 是链表的长度。需要遍历链表一次。
空间复杂度:O(1)。
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
真题点击此处:2. 两数相加
解题思路:
假设有两个非空的链表 l1 和 l2,它们分别表示两个非负整数的每一位数字,数字低位在链表头部。我们需要将这两个链表表示的数字相加,并以相同形式返回一个新的链表。
具体解题思路可以总结为以下几点:
这种方法利用了链表的特性,顺序处理两个链表对应位置的数字,并考虑进位的情况,最终得到表示两数相加结果的新链表。
以下为代码实现:
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *head = nullptr, *tail = nullptr;
int carry = 0;
while(l1 || l2){
int n1 = l1 ? l1->val : 0;
int n2 = l2 ? l2->val : 0;
int sum = n1 + n2 + carry;
if(!head){
head = tail = new ListNode(sum % 10);
}else{
tail->next = new ListNode(sum % 10);
tail = tail->next;
}
carry = sum / 10;
if(l1){
l1 = l1->next;
}
if(l2){
l2 = l2->next;
}
}
if(carry > 0){
tail->next = new ListNode(carry);
}
return head;
}
};
时间复杂度:O(max(m,n)),其中 m 和 n 分别为两个链表的长度。我们要遍历两个链表的全部位置,而处理每个位置只需要 O(1) 的时间。
空间复杂度:O(1)。注意返回值不计入空间复杂度。