目录
一、移除链表元素
给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点
输入:head = [1, 2, 6, 3, 4, 5, 6], val = 6
输出:[1, 2, 3, 4, 5]
示例 2:输入:head = [ ], val = 1
输出:[ ]
示例 3:输入:head = [7, 7, 7, 7], val = 7
输出:[ ]
链接:https://leetcode-cn.com/problems/remove-linked-list-elements
思路动图: 利用双指针法,先找到要删除的节点并保存前一个结点的位置
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* prev= NULL;
struct ListNode* next = head;
while(next != NULL)
{
//不相等,向后找
if(next->val != val)
{
prev = next;
next = next->next;
}
//找到了
else
{
//如果节点元素全部相等的情况
if(next == head)
{
head = next->next;
free(next);
next = head;
}
//不相等,先链接到要删除节点的下一个结点,在释放
else
{
prev->next = next->next;
free(next);
next = prev->next;
}
}
}
return head;
}
二、反转链表
给你单链表的头节点
head
,请你反转链表,并返回反转后的链表。
思路动图: 三指针法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head){
//链表为空
if(head == NULL)
return NULL;
//创建三个指针
struct ListNode* cur,*prev,*next;
cur = NULL;
prev = head;
next = head->next;
while(prev)
{
prev->next = cur;
cur = prev;
prev = next;
if(next)
next = next->next;
}
return cur;
}
三、链表的中间结点
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
链接:https://leetcode-cn.com/problems/middle-of-the-linked-list
思路: 快慢指针法
快、慢指针同时从头结点出发,慢指针一次走一个节点,快指针一次走两个节点;此时会有两种情况:
情况1:
情况2:
思路动图:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* slow,* fast;
slow = fast = head;
while(fast && fast -> next)
{
fast = fast -> next -> next;
slow = slow -> next;
}
return slow;
}
四、链表中倒数第k个结点
这是牛客网的一道题
输入一个链表,输出倒数第k个结点
示例:
输入:1, { 1, 2, 3, 4, 5 }
返回值:{ 5 }
思路: 快慢指针法
我们要找到倒数第 k 个结点,以 k = 3 为例,我们只要保证快指针与慢指针之间相差两步,直到快指针走到尾结点,返回慢指针,此时就是倒数第 k 个结点;
从上图可以看出只要保证两步之遥,当fast指针走到空时,slow指针就是倒数第k个指针,所以无论k是多少只要两指针间距为k-1即可;
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
struct ListNode* slow, *fast;
slow = fast = pListHead;
while(k--)
{
if(fast == NULL)
{
return NULL;
}
fast = fast -> next;
}
while(fast)
{
slow = slow -> next;
fast = fast -> next;
}
return slow;
}
五、合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的 ;
输入:l1 = [ 1, 2, 4 ], l2 = [ 1, 3, 4 ]
输出:[ 1, 1, 2, 3, 4, 4]
示例 2:输入:l1 = [ ], l2 = [ ]
输出:[ ]
示例 3:输入:l1 = [ ], l2 = [ 0 ]
输出:[ 0 ]提示:
两个链表的节点数目范围是 [ 0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists
思路动图:
两个链表进行比较,谁小就拿谁,组成新的链表;
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
//任何一个链表为空,就返回另外一个
if(list1 == NULL)
return list2;
if(list2 == NULL)
return list1;
//创建两个节点,用来存储新链表
struct ListNode* head = NULL;
struct ListNode* tail = NULL;
head = tail =(struct ListNode*)malloc(sizeof(struct ListNode));
while(list1 && list2)
{
if(list1->val > list2->val)
{
//取list2
tail->next = list2;
tail = list2;
list2 = list2->next;
}
else
{
//取list1
tail->next = list1;
tail = list1;
list1 = list1->next;
}
}
//循环结束,会存在一个链表没走完的情况
if(list1)
tail->next = list1;
if(list2)
tail->next = list2;
struct ListNode* newlist = head->next;
free(head);
return newlist;
}