前言:
今天我们继续做链表算法题,相比于上次的QJ1,这次选的题更容易、基础一点。如有错误,请评论指出,制作不易,还望给个关注点赞哦!🤗🤗
下面是所讲算法题答题链接,大家可以先做一下,再看我的解答🤓💡👆
1、移除链表元素
https://leetcode.cn/problems/remove-linked-list-elements/description/
2、反转链表
https://leetcode.cn/problems/reverse-linked-list/description/
3、链表的中间结点
https://leetcode.cn/problems/middle-of-the-linked-list/description/
4、合并两个有序链表
https://leetcode.cn/problems/merge-two-sorted-lists/description/

一、移除链表元素
1、答案
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
//创建新链表
ListNode* newHead,*newTail;
newHead=newTail=NULL;
//遍历原链表
ListNode* pcur=head;
while(pcur)
{
if(pcur->val!=val)
{
if(newHead==NULL)
{
newHead=newTail=pcur;
}
else
{
//链表不为空
newTail->next=pcur;
newTail=newTail->next;
}
}
pcur=pcur->next;
}
if(newTail)
{
newTail->next=NULL;
}
return newHead;
}
2、解析
这个题的解决方法是创建一个新链表,在遍历原链表,找到值不为val的节点,并把该节点往新链表中进行尾插。
二、反转链表
1、答案
typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
if(head==NULL)
{
return head;
}
ListNode *n1,*n2,*n3;
n1=NULL,n2=head,n3=n2->next;
while(n2)
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3)
n3=n3->next;
}
return n1;
}
2、解析
思路一:将链表头插到新链表上。(链表的头插法)
思路二:创建三个指针,直接在原链表上修改指针的方向。(上述答案为该思路的答案)
三、求链表的中间结点
1、答案
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
ListNode *slow=head,*fast=head;
//慢指针每次走一步,快指针每次走两步
while(fast&&fast->next)//等价于(fast!=NULL&&fast->next!=NULL)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
2、解析
思路一:第一次循环,求出链表的总长度,计算中间节点的位置。第二次循环,根据中间节点的位置求中间结点。
思路二:利用快慢指针(上一篇博客中讲过快慢指针,链表QJ1),快指针走两步,慢指针走两步。(上面的代码为该思路的答案)。
四、合并两个有序链表
1、答案
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1,struct ListNode* list2)
{
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
//动态申请
ListNode* newHead,*newTail;
newHead=newTail=(ListNode*)malloc(sizeof(ListNode));
ListNode* l1=list1;
ListNode* l2=list2;
while(l1 && l2)
{
if(l1->val < l2->val)
{
newTail->next=l1;
newTail=newTail->next;
l1=l1->next;
}
else
{
newTail->next=l2;
newTail=newTail->next;
l2=l2->next;
}
}
if(l1)
newTail->next=l1;
if(l2)
newTail->next=l2;
ListNode* ret=newHead->next;
free(newHead);
newHead=NULL;
return ret;
}
2、解析
思路:创建新链表,遍历两个原链表,比较大小,谁小谁就尾插到新链表中。
注意在上面的代码中,为方便我们在创建新链表时使用动态申请新结点,令头节点不为空,最后应该释放动态申请的新结点。把结点的值给另一个新建节点,再释放头结点。
五、链表分割
1、答案
#include <cstddef>
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
//创建两个非空链表:小链表和大链表
ListNode* lessHead,*lessTail;
lessHead=lessTail=(ListNode*)malloc(sizeof(ListNode));
ListNode* greaterHead,*greaterTail;
greaterHead=greaterTail=(ListNode*)malloc(sizeof(ListNode));
//遍历链表(小于x的尾插到小链表,大于x的尾插到大链表)
ListNode*pcur=pHead;
while(pcur)
{
if(pcur->val<x)
{
lessTail->next=pcur;
lessTail=lessTail->next;
}
else
{
greaterTail->next=pcur;
greaterTail=greaterTail->next;
}
pcur=pcur->next;
}
//将大链表的尾结点的next指针置为NULL;
greaterTail->next=NULL;
//大小链表首尾相连
lessTail->next=greaterHead->next;
ListNode* ret=lessHead->next;
free(lessHead);
free(greaterHead);
lessHead=greaterHead=NULL;
return ret;
}
};
2、解析
思路:创建两个新链表,小于x的值尾插到一个链表中,大于x的值尾插到一个链表中,最后小链表的尾链接大链表的头,注意最后将大链表的尾指针的next指针指向NULL,否则陷入死循环;
六、链表的回文结构
1、答案
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
int arr[900]={0};
ListNode* pcur=A;
int i=0;
//遍历链表,将链表中每个结点中的数值保存在数值中
while(pcur)
{
arr[i++]=pcur->val;
pcur=pcur->next;
}
//i即节点的个数
//找中间结点,判断是否为回文数字
int left=0;
int right=i-1;
while(left<right)
{
if(arr[left]!=arr[right])
{
return false;
}
left++;
right--;
}
return true;
}
};
2、解析
思路:创建新的数组,遍历原链表,将原链表的值放入数组,在数组中判断是否为回文结构;