题单:
一,移除链表元素
题目描述
给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点 。
题目接口:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
}
题目解答:
做这道题需要分三种情况:
1.当链表为空链表时直接返回NULL便可。
2.当链表的头节点就是要删除的节点时就执行头删的逻辑,即:
当遇到这个用例时,需要删除的链表元素为7时便走第一个循环进行头删。不断调整head指针的指向。直到head指针指向NULL。
3.当要删除的节点不是头节点时,需要执行另一个删除元素的逻辑。这个逻辑需要用到三个指针:prev(要删除节点的前一个指针),cur(当前节点指针),next(要删除节点的下一个指针)。
在定义时将prev初始化为NULL,cur初始化为head,next是cur指向的next(前提条件是cur不为NULL)。
即:
要删除的元素为2.
删除操作与不删除时的操作也是不一样的,删除时:
1.prev不能动,动了就会与cur重叠。
2.next要在cur不为NULL时才能动。
不是删除操作时:
1.三个指针一起动
2.next要在cur不为NULL时才能动。
代码如下:
解题代码:
struct ListNode* removeElements(struct ListNode* head, int val){
if(head == NULL)
return NULL;
//当头节点为要删除的值时
struct ListNode* next = head->next;
while(head&&head->val == val)
{
free(head);
head = next;
if(head)
next = head->next;
}
//当要删除的节点是另外的节点时
struct ListNode* prev = NULL;
struct ListNode* cur = head;
while(cur)
{
if(cur->val == val)
{
free(cur);
prev ->next = next;
cur = next;
if(cur)
next = cur->next;
}
else
{
prev = cur;
cur = next;
if(cur)
next = cur->next;
}
}
return head;
}
二,链表的中间节点
题目描述:
给你单链表的头结点
head
,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
题目接口:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* middleNode(struct ListNode* head){
}
题目解答:
要找到链表的中间节点,需要定义两个指针:1.快指针 2.慢指针
这两个指针在一开始时指向同一个节点,但在移动的过程中快指针的移动速度是慢指针的两倍。当快指针走到结尾时慢指针就走到了中间节点处。
解题代码:
struct ListNode* middleNode(struct ListNode* head){
//当链表为NULL时返回NULL
if(head == NULL)
return NULL;
//当链表只有一个节点时返回这一个节点即可
if(head->next == NULL)
return head;
//当链表内有多个节点时定义快慢指针,走快慢指针解法
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
三,查找链表的第k个节点
题目描述:
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
题目接口:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* getKthFromEnd(struct ListNode* head, int k){
}
题目解答:
寻找链表的倒数第k个节点要分三种情况:
1.当链表为NULL时返回NULL
2.当k大于链表的长度时返回NULL
3.当前两种情况没有出现时就在fast比slow指针多走k步以后继续走直到fast指向NULL此时slow便指向倒数第k个节点,返回slow即可。
解题代码:
struct ListNode* getKthFromEnd(struct ListNode* head, int k){
//当链表为NULL时
if(head == NULL)
return NULL;
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast&&k)
{
fast = fast->next;
k--;
}
//当k的大小大于链表的长度时
if(k>0)
return NULL;
//fast比slow的步长大k当fast指向NULL时,slow指向链表的倒数第k个节点
while(fast)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
四,反转链表
题目描述:
给定单链表的头节点
head
,请反转链表,并返回反转后的链表的头节点。
题目接口:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head){
}
题目解答:
反转链表这道题需要分三种情况来讨论:
1.链表为NULL时直接返回NULL即可。
2.链表只有一个节点时直接返回头节点即可
3.当链表内有多个节点时需要用到三个指针:prev,cur,next。通过这三个指针来对链表的指向进行反转,最后返回prev得到的便是反转后的指针。
解答代码:
struct ListNode* reverseList(struct ListNode* head){
//当链表为NULL时直接返回NULL
if(head==NULL)
{
return NULL;
}
//当链表只有一个节点时
if(head->next == NULL)
{
return head;
}
//当链表内有多个节点时
struct ListNode* prev = NULL;
struct ListNode* cur = head;
struct ListNode* next = head->next;
while(cur)
{
cur->next = prev;
prev = cur;
cur = next;
if(cur)
next = cur->next;
}
return prev;
}
五,链表的合并
题目描述:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
题目接口:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
}
题目分析:
要实现两个链表升序的合并需要讨论三种情况:
1.两个链表都是空链表时返回NULL
2.当两个链表中有一个链表为NULL时返回那个非空链表
3.当两个链表都不为NULL时要通过对比实现取小的尾插。在其中一个链表变成空链表时将另外一个非空的链表连接到新链表的后面便完成了链接两个链表的操作。
解题代码:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
//当两个链表都为NULL时直接返回NULL
if(list1==NULL&&list2==NULL)
{
return NULL;
}
//当两个链表中有一个为NULL一个不为NULL时返回不为NULL的
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
//当两个链表都不为NULL时取小的尾插
struct ListNode* newhead = NULL;
struct ListNode* tail = NULL;
while(list1&&list2)
{
if(list1->val<list2->val)
{
if(newhead == NULL)
{
newhead = tail = list1;
list1 = list1->next;
}
else
{
tail->next = list1;
list1 = list1->next;
tail = tail->next;
}
}
else
{
if(newhead == NULL)
{
newhead = tail = list2;
list2 = list2->next;
}
else
{
tail->next = list2;
list2 = list2->next;
tail = tail->next;
}
}
}
if(list1)
tail->next = list1;
if(list2)
tail->next = list2;
return newhead;
}