移除链表元素
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点
指针法
思路:创建指针cur遍历链表, 当cur->next指向的val为val时,用prev指针保存cur->next,然后
cur->next=cur->next->next,在把prev指向的空间free掉
那么会有两种方法:一种是不设哨兵位,另一种是设了哨兵位
不设哨兵位:要考虑头节点是不是含有val的节点
struct ListNode* removeElements(struct ListNode* head, int val){
typedef struct ListNode ListNode;
//如果(头节点存在且)头节点是val
while( head && head->val==val)
{
ListNode* tmp=head;
head=head->next;
free(tmp);
tmp=NULL;
}
ListNode* cur=head;
while(cur && cur->next!=NULL)
{
if(cur->next->val==val)
{//删除Val的节点
ListNode* prev=cur->next;
cur->next=cur->next->next;
free(prev);
}
else
{
cur=cur->next;//迭代
}
}
return head;//返回头节点噢
}
设哨兵位:设了哨兵位就少了考虑头节点是不是含val的节点!
设哨兵位phead,最后返回phead->next即可!
struct ListNode* removeElements(struct ListNode* head, int val){
typedef struct ListNode ListNode;
//给哨兵位开空间
ListNode* phead=(ListNode*)malloc(sizeof(ListNode));
phead->next=head;//连接链表
ListNode* cur=phead;
while(cur->next!=NULL)
{
if(cur->next->val==val)
{//删除Val的节点
ListNode* prev=cur->next;
cur->next=cur->next->next;
free(prev);
}
else
{
cur=cur->next;//迭代
}
}
return phead->next;//返回phead->next节点噢
}
反转链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
双指针法
struct ListNode* reverseList(struct ListNode* head){
typedef struct ListNode ListNode;
ListNode* cur=head;
ListNode*prev=NULL;
while(cur!=NULL)
{
ListNode*tmp=cur->next;
cur->next=prev;//链接
//迭代
prev=cur;
cur=tmp;
}
return prev;//返回prev节点
}
递归法
struct ListNode* reverse (struct ListNode* prev,struct ListNode* cur)
{
if(cur==NULL)
return prev;
struct ListNode* tmp=cur->next;//保存cur的下一个节点
cur->next=prev;//链接
//迭代用递归 prev=cur, cur=tmp
return reverse(cur,tmp);
}
struct ListNode* reverseList(struct ListNode* head){
// struct ListNode*prev=NULL;
// struct ListNode*cur=head;
return reverse(NULL,head);
}
两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
注意!这道题是两个节点两两交换节点,然后到下一对节点两两交换…
如果不满足一对节点时就不交换!
我们要操作第一个节点,所以我们得在前面创建哨兵节点(phead),然后用cur指针指向它;
第一步:cur->next=cur->next->next;这时候我们就失去了cur->next这个节点的地址了,所以我们要先在第一步前保存cur->next的地址: tmp1=cur->next
第二步:cur->next=tmp1;
第三步:tmp1->next=cur->next->next->next???有没有发现经过第一步和第二步我们也找不到cur->next->next->next的节点了所以我们要在第一步前先保存cur->next->next->next的地址:
tmp2=cur->next->next->next
第三步:tmp1->next=tmp2
递归条件就是cur=cur->next->next(因为要操作后两个节点,所以指针要在前一个节点)
终止条件就是操作的两个节点都要存在:cur!=NULL && cur->next!=NULL
最后返回头:return phead->next;
具体实现看下面代码:
迭代法
struct ListNode* swapPairs(struct ListNode* head){
typedef struct ListNode ListNode;
ListNode* phead=(ListNode*)malloc(sizeof(ListNode));
phead->next=head;
ListNode*cur=phead;
while(cur->next!=NULL&& cur->next->next!=NULL)
{
ListNode*tmp1=cur->next;//保存节点
ListNode*tmp2=cur->next->next->next;//保存节点
cur->next=cur->next->next;//第一步
cur->next->next=tmp1;//第二步
tmp1->next=tmp2;//第三步
cur=cur->next->next;//迭代
}
return phead->next;//把头传回去
}
递归法
思路跟迭代法一样
struct ListNode* swapPairs(struct ListNode* head){
if(head==NULL || head->next==NULL)
{
return head;//终止条件
}
struct ListNode*nhead=head->next;//保存head的下一个结点
head->next=swapPairs(nhead->next);//寻找head连接的下一对的头节点
nhead->next=head;
return nhead;
}
删除链表的倒数第N个节点
创建一个fast点,一个slow结点,fast先走n步,然后fast和slow一起走,当fast为空时,slow指向的结点就是要删除的结点,提前保存好slow的前一个结点(用cur保存),然后cur->next=slow->next再把slow指向的空间free掉,最后返回头结点即可。(fast指针和slow指针永远间隔n个结点)
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
typedef struct ListNode ListNode;
ListNode*fast=head;
ListNode*slow=head;
ListNode*cur=NULL;
while(n--)
{
fast=fast->next;
}
if(fast==NULL)//考虑链表只有一个结点
{
head=head->next;
return head;
}
while(fast!=NULL)
{
fast=fast->next;
cur=slow;
slow=slow->next;
}
cur->next=slow->next;
return head;
}
链表相交
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
设链表A长度为lengthA,链表B长度为lengthB,然后比较找出最长和最短,向减后得到两个链表同样的起点,让curl遍历长的链表先遍历长链表比短链表多出的部分,然后让curs指针和curl指针一起遍历,相等即有交点。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
typedef struct ListNode ListNode;
ListNode*curl=headA;
ListNode*curs=headB;
int lengthA=0;
int lengthB=0;
int index=0;
while(curl)
{
lengthA++;
curl=curl->next;
}
while(curs)
{
lengthB++;
curs=curs->next;
}
if(lengthA>lengthB)
{
index=lengthA-lengthB;//算差值
curl=headA;
curs=headB;
}
else
{
index=lengthB-lengthA;//算差值
curs=headA;
curl=headB;
}
while(index--)
{
curl=curl->next;
}
while(curl)
{
if(curl==curs)
{
return curs;
}
curl=curl->next;
curs=curs->next;
}
return NULL;
}
环形链表
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。
设一个cur指针一次走两步,prev指针一次走一步,当cur指针进到环里并且到到(即将cur遇见prev)相遇点,此时cur走了x+y步,等到cur和prev相遇时,prev走了x+y步;cur转了n圈,所以是走了n*(y+z)+x+y步;加上cur走的路程是prev的两倍,所以得等式
2(x+y)=n (y+z)+x+y 简化得x=(n-1) (y+z)+z 即n=1*时,x=z;
当prev也进到环里了,cur走两步,prev走一步,等于cur一步一步靠近prev,所以不怕错过噢~~~(就像你终究会遇到你的心上人那样,不会错过~ ~ ~)
struct ListNode *detectCycle(struct ListNode *head) {
typedef struct ListNode ListNode;
ListNode*cur=head;
ListNode*prev=head;
while(cur&& cur->next)
{
cur=cur->next->next;//cur走两步
prev=prev->next;//prev走一步
if(cur==prev)//相遇在相遇点
{
ListNode*phead=cur;//相遇点
ListNode*shead=head;//表头
while(phead!=shead)//相遇在入环处
{
phead=phead->next;
shead=shead->next;
}
return shead;//返回入环处
}
}
return NULL;//如果没有环记得返回空
}
总结
以上内容是我看[代码随想录]并做题后的感想和思路,如果对你有帮助的话不妨给个小小的👍~~~
代码随想录链接:代码随想录