主页:114514的代码大冒
qq:2188956112(欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ )
Gitee:庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com
文章目录
目录
文章目录
前言
一、移除链表元素
二、反转链表
三,链表的中间结点
四,剑指 Offer 22. 链表中倒数第k个节点
五,合并两个有序链表
总结
前言
祝武运昌隆!!!
一、移除链表元素
描述:
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
示例一:
输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]
示例二:
输入:head = [], val = 1 输出:[]
输入:head = [7,7,7,7], val = 7 输出:[]
思路:
这个题目我们因为涉及单链表的节点删除操作,所以我们要知道需要删除的节点的前一个节点的位置,这样才能完成删除操作,所以我们设置了两个指针,一个prev表示前一个位置,一个cur表示当前节点位置,ok,我们接下来看解析图(注意边界问题,诸如单节点,空链表的处理)
如图:
上图把链表结构画成了数组,将就着看吧
代码:
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* prev = NULL;
struct ListNode* cur = head;
if(head == NULL)
{
return NULL;
}
while(cur != NULL)
{
if(cur->val != val)
{
prev = cur;
cur = cur->next;
}
else
{
if (prev == NULL)
{
head = head->next;
free(cur);
cur = head;
}
else
{
prev->next = cur->next;
free(cur);
cur = prev->next;
}
}
}
return head;
}
二、反转链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例一:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例二:
输入:head = [1,2] 输出:[2,1]
示例三:
输入:head = [] 输出:[]
思路:
我们这题的基本题意就是让第一个节点指向空,第二个节点指向第一个节点,第三个节点指向第二个节点,以此类推,最后,本来的尾节点成了头结点,这题是个经典题目,很多的公司在面试的时候都喜欢出这么一个类型的题目,在这里,我们对于本题采用多指针的办法(分别为prev,cur,next),OKOK,我们直接上图:
代码:
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* cur = head;
if(cur == NULL)
{
return NULL;
}
struct ListNode* prev = NULL;
struct ListNode* next = cur->next;
if(cur->next == NULL)
{
return cur;
}
while(cur)
{
cur->next = prev;
prev = cur;
cur = next;
if(next != NULL)
next = cur->next;
}
return prev;
}
三,链表的中间结点
描述:
给你单链表的头结点 head
,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例一:
输入:head = [1,2,3,4,5] 输出:[3,4,5] 解释:链表只有一个中间结点,值为 3 。
示例二:
输入:head = [1,2,3,4,5,6] 输出:[4,5,6] 解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。
思路:
设置快慢指针,快指针的速度是慢指针的二倍,也就是说在快指针指向链尾时,慢指针就会指向链的中间位置,这里对于奇数个节点与偶数个节点的处理方式是不一样的,涉及到边界为问题,我们具体通过画图来分析:
代码:
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* fast = head;
struct ListNode* slow = head;
if(head == NULL)
{
return NULL;
}
if(head->next == NULL )
{
return head;
}
while(fast && fast->next )
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
四,剑指 Offer 22. 链表中倒数第k个节点
描述:
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
示例一:
给定一个链表: 1->2->3->4->5, 和 k = 2. 返回链表 4->5.
思路:
设置快慢指针,快指针提前走k步,然后快慢指针同时逐节点前进,走到链尾,慢指针指向的就是倒数第k个节点,此题奇数偶数不影响,如图所示:
代码:
struct ListNode* getKthFromEnd(struct ListNode* head, int k){
struct ListNode* hd = head;
struct ListNode* fast = head;
struct ListNode* slow = head;
if(head == NULL)
{
return NULL;
}
while(k--)
{
fast = fast->next;
if(fast == NULL)
{
break;
}
}
while(fast)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
五,合并两个有序链表
描述:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例一:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例二:
输入:l1 = [], l2 = [] 输出:[]
示例三:
输入:l1 = [], l2 = [0] 输出:[0]
思路:
我们自己弄一个头结点,然后将这两个链表逐个节点比较,小的就连在新的头结点后面,以此类推
如此就完成了对链表的合并,函数返回的应当是我们弄的头结点的下一个节点
如图:
代码:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* rethead = head;
struct ListNode* l1 = list1;
struct ListNode* l2 = list2;
if((l1 == NULL)&&(l2 == NULL))
{
return NULL;
}
while(l1 && l2)
{
if(l1->val > l2->val)
{
head->next = l2;
head = head->next;
l2 = l2->next;
}
else
{
head->next = l1;
head = head->next;
l1 = l1->next;
}
}
if(l1 != NULL)
{
head->next = l1;
}
else if(l2 != NULL)
{
head->next = l2;
}
else
{
;
}
return rethead->next;
}
总结
OK,这就是本次链表的全部内容了,链表题在数据结构中真的属于比较简单的部分了,大家手撕红黑树的闲暇之余,可以随便找几个链表题放松放松