🔥个人主页:************************************************************************************************************************************************************************************************************************************************************胡萝卜3.0****************************************************************************************************************************************************************************************************************************************************************
🎬作者简介:C++研发方向学习者
📖个人专栏:************************************************************************************************************************************************************************************************************************************************************《C语言》、《数据结构》 、《C++干货分享》、LeetCode&牛客代码强化刷题****************************************************************************************************************************************************************************************************************************************************************
⭐️人生格言:不试试怎么知道自己行不行


目录
一、移除链表元素
1、题目描述

2、思路及代码
思路1:查找值为val的结点并返回该结点,删除指定位置上的结点
思路2:创建新链表,遍历原链表,将不为val的值尾插到新链表中

思路2转换成代码:
cpp
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
ListNode* newhead=NULL;
ListNode* newTail=NULL;
//遍历链表,将不为val的结点尾插到新链表中
ListNode* pcur=head;
while(pcur!=NULL)
{
if(pcur->val!=val)
{
//尾插
if(newhead==NULL)
{
newhead=newTail=pcur;
}
else{
newTail->next=pcur;
newTail=newTail->next;
}
}
pcur=pcur->next;
}
if(newTail!=NULL)
{
newTail->next=NULL;
}
return newhead;
}
时间复杂度为:O(N) 空间复杂度为:O(1)
二、反转链表
1、题目描述

2、思路及代码
思路1:创建新链表,遍历原链表,遍历到一个结点就头插到新链表中
将上面思路转换成代码:
cpp
//遍历链表,头插
typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
ListNode* newhead=NULL;
ListNode* pcur=head;
while(pcur!=NULL)
{
ListNode* next=pcur->next;
pcur->next=newhead;
newhead=pcur;
pcur=next;
}
return newhead;
}
时间复杂度为:O(N) 空间复杂度为:O(1)
思路2:创建三个指针,改变指针的指向

将上面思路转换成代码:
cpp
//思路2创建三个指针
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!=NULL)
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3!=NULL)
n3=n3->next;
}
return n1;
}
时间复杂度为:O(N) 空间复杂度为:O(1)
三、链表的中间结点
1、题目描述

2、思路及代码
思路1:遍历链表,求出链表的结点个数size,size/2为中间结点的个数,循环找中间结点,最后返回中间结点。
将上面的思路转换成代码:
cpp
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
//遍历求出结点个数
ListNode* pcur=head;
int size=0;
while(pcur!=NULL)
{
size++;
pcur=pcur->next;
}
int mid=size/2;
pcur=head;
while(mid--)
{
pcur=pcur->next;
}
return pcur;
}
时间复杂度为:O(N) 空间复杂度为:O(1)
思路2:创建快慢指针,快指针走两步,慢指针走一步,最终返回慢指针所在的结点位置

将上面的思路转换成代码:
cpp
//快慢指针
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
ListNode* fast=head;
ListNode* slow=head;
while(fast!=NULL&&fast->next!=NULL)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
时间复杂度为:O(N) 空间复杂度为:O(1)
四、合并两个有序链表
1、题目描述

2、思路及代码
思路:创建新链表,遍历两个链表,比较大小,小的往新链表中尾插
将上面思路转换成代码:
cpp
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=NULL;
ListNode* l1=list1;
ListNode* l2=list2;
while(l1&&l2)
{
if(l1->val>l2->val)
{
//较小的尾插
if(newhead==NULL)
{
newhead=newtail=l2;
}
else
{
newtail->next=l2;
newtail=newtail->next;
}
l2=l2->next;
}
else
{
if(newhead==NULL)
{
newhead=newtail=l1;
}
else
{
newtail->next=l1;
newtail=newtail->next;
}
l1=l1->next;
}
}
//跳出循环,需要判断那个链表没有遍历完
if(l1)
{
newtail->next=l1;
}
if(l2)
{
newtail->next=l2;
}
return newhead;
}
有没有uu发现上面的代码有点冗余,我们对上面的代码改进一下:
cpp
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=l2;
newtail=newtail->next;
l2=l2->next;
}
else
{
newtail->next=l1;
newtail=newtail->next;
l1=l1->next;
}
}
//跳出循环,需要判断那个链表没有遍历完
if(l1)
{
newtail->next=l1;
}
if(l2)
{
newtail->next=l2;
}
return newhead->next;
}
五、链表的回文结构
1、题目描述

2、思路及代码
思路1:创建新链表保存原链表所有的节点,反转新链表,比较新旧链表中的节点的值是否相同
将上面思路转换成代码:
cpp
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
ListNode* pcur=A;
//反转pcur链表
ListNode* n1,*n2,*n3;
n1=NULL;
n2=pcur;
n3=n2->next;
while(n2!=NULL)
{
n2->next=n1;
n1=n2;
n2=n3;
n3=n3->next;
}
//n1为反转后链表的头结点
while(n1!=NULL&&pcur!=NULL)
{
if(n1->val!=pcur->val)
{
return false;
}
n1=n1->next;
pcur=pcur->next;
}
return true;
}
};
思路2:题目中写到链表的长度不超过900,创建数组(大小不超过900),遍历链表,将链表中的值放入数组中,若数组为回文结构,那链表就为回文结构。
将上面思路转换成代码:
cpp
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
int arr[900];
//遍历链表
ListNode* pcur=A;
int i=0;
while(pcur)
{
arr[i++]=pcur->val;
pcur=pcur->next;
}
int left=0;
int right=i-1;
while(left<right)
{
if(arr[left]!=arr[right])
{
return false;
}
left++;
right--;
}
return true;
}
};
思路3(最正确的解法):找链表的中间节点,将中间节点作为新链表的头结点,反转新链表,遍历原链表和新链表,看对应的值是否相等。
将上面思路转换成代码:
cpp
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
ListNode* pcur=A;
//找链表的中间节点
ListNode* slow=pcur;
ListNode* fast=pcur;
while(fast!=NULL&&fast->next!=NULL)
{
slow=slow->next;
fast=fast->next->next;
}
//slow为中间节点
//反转
ListNode* n1,*n2,*n3;
n1=NULL,n2=slow,n3=n2->next;
while(n2!=NULL)
{
n2->next=n1;
n1=n2;
n2=n3;
n3=n3->next;
}
//比较原链表和反转之后的链表
while(n1!=NULL)
{
if(n1->val!=pcur->val)
{
return false;
}
n1=n1->next;
pcur=pcur->next;
}
return true;
}
};
六、相交链表
1、题目描述


2、思路及代码
思路:遍历两个链表,求出两个链表的长度,然后做差,得到长度差。比较两个链表的长度,得到较长的链表(这里可以使用假设法),先让较长链表走长度差步,然后两个链表同时走,比较对应结点的内容,如果相等,则说明相遇,返回该结点;如果遍历完,还没有相遇,则直接返回NULL。
将上面思路转换成代码:
cpp
typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
//遍历链表,求出两个链表的长度
ListNode* pa=headA;
ListNode* pb=headB;
int sizea=0,sizeb=0;
while(pa!=NULL)
{
sizea++;
pa=pa->next;
}
while(pb!=NULL)
{
sizeb++;
pb=pb->next;
}
//得到长链表的头节点
ListNode* shortlist=headA;
ListNode* longlist=headB;
if(sizea>sizeb)
{
shortlist=headB;
longlist=headA;
}
//先让长链表走长度差步
int size=abs(sizea-sizeb);
while(size--)
{
longlist=longlist->next;
}
//现在让两个链表同时走
while(longlist!=NULL&&shortlist!=NULL)
{
if(longlist==shortlist)
{
return longlist;
}
longlist=longlist->next;
shortlist=shortlist->next;
}
return NULL;
}
ok,本次单链表的相关OJ题就介绍到这,后面还会有更多的题目等着我们继续攻克!!!