36. 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。
数据范围
链表长度 [0,500]。
样例
输入:1->3->5 , 2->4->5
输出:1->2->3->4->5->5
解决方案:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* merge(ListNode* l1, ListNode* l2) {
auto dummy=new ListNode(-1),tail=dummy;
while(l1 && l2){
if(l1->val < l2->val){
tail=tail->next=l1;
l1=l1->next;
}
else{
tail=tail->next=l2;
l2=l2->next;
}
}
if(l1) tail->next=l1;
if(l2) tail->next=l2;
return dummy->next;
}
};
28. 在O(1)时间删除链表结点
给定单向链表的一个节点指针,定义一个函数在O(1)时间删除该结点。
假设链表一定存在,并且该节点一定不是尾节点。
数据范围
链表长度[1,500]。
样例
输入:链表 1->4->6->8
删掉节点:第2个节点即6(头节点为第0个节点)
输出:新链表 1->4->8
解决方案:
// Definition for singly-linked list.
// struct ListNode {
// int val;
// ListNode *next;
// ListNode(int x) : val(x), next(NULL) {}
// };
class Solution {
public:
void deleteNode(ListNode* node) {
node->val=node->next->val;//伪装值
node->next=node->next->next;//伪装地址
//*(node)=*(node->next);//整体复制
}
};
35. 反转链表
定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。
思考题:
请同时实现迭代版本和递归版本。
数据范围
链表长度 [0,30]。
样例
输入:1->2->3->4->5->NULL
输出:5->4->3->2->1->NULL
解决方案:
递归版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head || !head->next) return head;
auto trail=reverseList(head->next);
head->next->next=head;
head->next=NULL;
return trail;
}
};
迭代版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head || !head->next) return head;
auto a=head,b=a->next;
while(b){
auto c=b->next;
b->next=a;
a=b;
b=c;
}
head->next=NULL;
return a;
}
};
66. 两个链表的第一个公共结点
输入两个链表,找出它们的第一个公共结点。
当不存在公共节点时,返回空节点。
数据范围
链表长度 [1,2000]。
保证两个链表不完全相同,即两链表的头结点不相同。
样例
给出两个链表如下所示:
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
输出第一个公共节点c1
第一行为第一个链表;
第二行为第二个链表;
第三行为第二个链表插到第一个链表哪个节点上;
算法思路:

a,b,c分别为链表不同段的长度
①两个链表有公共点
p是遍历headA上的指针,走过的路径为:a-c-b 走过的路程为:a+b+c
q是遍历headB上的指针,走过的路径为:b-c-a 走过的路程为:a+b+c
当p,q相遇时,相遇的点为公共点
②两个链表没有公共点
p是遍历headA上的指针,走过的路径为:a-b 走过的路程为:a+b
q是遍历headB上的指针,走过的路径为:b-a 走过的路程为:a+b
当p,q走完时(路程相等),为空节点
时间复杂度O(n)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) {
auto p=headA,q=headB;
while(p!=q){
if(p) p=p->next;
else p=headB;
if(q) q=q->next;
else q=headA;
}
return p;
}
};
29. 删除链表中重复的节点
在一个排序的链表中,存在重复的节点,请删除该链表中重复的节点,重复的节点不保留。
数据范围
链表中节点 val 值取值范围 [0,100]。
链表长度 [0,100]。
样例1
输入:1->2->3->3->4->4->5
输出:1->2->5
样例2
输入:1->1->1->2->3
输出:2->3
解决方案:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* head) {
auto dummy=new ListNode(-1);
dummy->next=head;
auto a=dummy;
while(a->next){
auto b=a->next;
while(b && a->next->val==b->val) b=b->next;
if(a->next->next==b) a=a->next;
else a->next=b;
}
return dummy->next;
}
};