目录
一、链表的中间节点
1.1 题目
1.2 题解
1.3 收获
二、移除链表元素
2.1 题目
2.2 题解
2.3 收获
2.4递归详解
三、反转链表
3.1 题目
3.2 题解
3.3 解释
四、合并两个有序列表
4.1 题目
4.2 题解
4.3 递归详解
声明:本文所有题目均摘自leetcode
一、链表的中间节点
1.1 题目
给你单链表的头结点
head
,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
1.2 题解
struct ListNode* middleNode(struct ListNode* head) {
struct ListNode* slow=head;
struct ListNode* fast=head;
while(fast!=NULL&&fast->next!=NULL)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
1.3 收获
- 快慢指针的用法:
- 链表长度为奇数: 当快指针走到尾节点时,慢指针正好走到中间节点。
- 链表长度为偶数: 当快指针走到NULL时,慢指针正好走到第二个中间节点。
二、移除链表元素
2.1 题目
给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点 。
2.2 题解
//创建虚拟节点法
struct ListNode* removeElements1(struct ListNode* head, int val) {
struct ListNode* dummyHead = malloc(sizeof(struct ListNode));
dummyHead->next = head;
struct ListNode* temp = dummyHead;
while (temp->next != NULL) {
if (temp->next->val == val) {
temp->next = temp->next->next;
}
else {
temp = temp->next;
}
}
return dummyHead->next;
}
//创建新链表法
struct ListNode* removeElements3(struct ListNode* head, int val) {
struct ListNode* phead = NULL;
struct ListNode* ptail = NULL;
struct ListNode* pcur = head;
while (pcur) {
if (pcur->val != val) {
if (phead == NULL) {
phead = ptail = pcur;
}
else {
ptail->next = pcur;
ptail = ptail->next;
}
}
pcur = pcur->next;
}
if (phead) {
ptail->next = NULL;
}
return phead;
}
//双指针法
struct ListNode* removeElements(struct ListNode* head, int val) {
while (NULL != head && head->val == val) {
head = head->next;
}
struct ListNode* pcur = head;
struct ListNode* prev = head;
while (pcur)
{
if (pcur->val != val)
{
prev = pcur;
}
else
{
prev->next = pcur->next;
}
pcur = pcur->next;
}
return head;
}
//递归做法
struct ListNode* removeElements2(struct ListNode* head, int val) {
if (head == NULL) {
return head;
}
head->next = removeElements(head->next, val);
if (head->val == val)
{
return head->next;
}
else
{
return head;
}
}
2.3 收获
- 创建虚拟头节点:好处是可以只维护一个指针
- 创建新链表法:思路简单:仅仅为挑选符合条件的数据复制即可
- 双指针法:保存前一个链表的指针
2.4递归详解
- 停止条件:当遍历链表的指针为空时。
- 如何递归:判断节点值是否等于给定值,并决定是否要删除。
三、反转链表
3.1 题目
给你单链表的头节点
head
,请你反转链表,并返回反转后的链表。
3.2 题解
struct ListNode* reverseList(struct ListNode* head) {
if (head == NULL) {
return head;
}
struct ListNode* a = NULL;
struct ListNode* b = head;
struct ListNode* c = head->next;
while (b) {
b->next = a;
a = b;
b = c;
if (c) {
c = c->next;
}
}
return a;
}
3.3 解释
三指针法:循环保留三个指针,修改朝向即可;
四、合并两个有序列表
4.1 题目
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
4.2 题解
//创建新链表法
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
if (list1 == NULL)
{
return list2;
}
if (list2 == NULL)
{
return list1;
}
if (list1 == NULL && list2 == NULL)
{
return NULL;
}
struct ListNode* l1 = list1;
struct ListNode* l2 = list2;
struct ListNode* newhead;
struct ListNode* newtail;
newhead = newtail = NULL;
while (l1 && l2)
{
if (l1->val < l2->val)
{
if (newhead == NULL)
{
newhead = newtail = l1;
}
else
{
newtail->next = l1;
newtail = newtail->next;
}
l1 = l1->next;
}
else
{
if (newhead == NULL)
{
newhead = newtail = l2;
}
else
{
newtail->next = l2;
newtail = newtail->next;
}
l2 = l2->next;
}
}
if (l1 == NULL && l2 != NULL)
{
newtail->next = l2;
while (l2->next)
{
l2 = l2->next;
}
newtail = l2;
}
if (l2 == NULL && l1 != NULL)
{
newtail->next = l1;
while (l1->next)
{
l1 = l1->next;
}
newtail = l1;
}
return newhead;
}
//递归
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
struct ListNode* l1 = list1;
struct ListNode* l2 = list2;
if (l1 == NULL) {
return l2;
}
if (l2 == NULL) {
return l1;
}
if (list1 == NULL && list2 == NULL)
{
return NULL;
}
if (l1->val <= l2->val) {
l1->next = mergeTwoLists(l1->next, l2);
return l1;
}
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
4.3 递归详解
- 停止条件:当两个链表都为空时。
- 如何递归:我们判断两个头结点哪个更小,然后较小结点的 next 指针指向其余结点。