一、两两交换链表中的节点
本题主要理解递归和创建虚拟头结点两个方法,主要是理清楚指针指向,这个是最重要的一步:
新链表展开后就是cur->2->1->3->4->5->NULL ,下一次需要跳到“1”位置继续遍历。
struct ListNode* swapPairs(struct ListNode* head) {
struct ListNode* newhead = (struct ListNode*)malloc(sizeof(struct ListNode));
newhead->next = head;
//终止条件:1 如果是空链表; 2 偶数个链表 3 奇数个链表
struct ListNode* cur = newhead;
while(cur->next !=NULL && cur->next->next != NULL)
{
struct ListNode* tmp = cur->next;//第一个节点
struct ListNode* tmp_1 = cur->next->next->next;//记录下第三个节点
/**画图比较清晰**/
cur->next = cur->next->next;
cur->next->next = tmp;
cur->next->next->next = tmp_1;
cur = cur->next->next;
}
return newhead->next;//一开始head 已经交换,注意头结点位置
}
另外一个方法是递归,递归思路可以这样理解,找到最后一次迭代,往前推:
struct ListNode* swapPairs(struct ListNode* head){
//递归结束条件:头节点不存在或头节点的下一个节点不存在。此时不需要交换,直接返回head
if(!head || !head->next)
return head;
//创建一个节点指针类型保存头结点下一个节点
struct ListNode *newHead = head->next;
//更改头结点+2位节点后的值,并将头结点的next指针指向这个更改过的list
head->next = swapPairs(newHead->next);
//将新的头结点的next指针指向老的头节点
newHead->next = head;
return newHead;
}
/**上面是代码随想录的写法**/
二、.删除链表的倒数第N个节点
删除倒数第N个节点,用双指针的办法,首先fast向前进N+1个节点,slow=0位置处,当fast==NULL时候,fast移动了LEN-N个,slow同步移动了LEN-N个,位置来到了倒数N位置的前一个,这样就能释放掉N个节点。
/**删除链表倒数第N个,用快慢指针**/
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
//创建新节点,用来处理头结点,方便统一处理头结点。
struct ListNode* dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode));
dummyHead->next = head;
struct ListNode* slow = dummyHead;
struct ListNode* fast = dummyHead;
int setp = 0;
while(fast)
{
fast = fast->next;
if(n== setp)
{
break;
}
setp++;
}
while(fast)
{
slow = slow->next;
fast = fast->next;
}
/**删除节点**/
struct ListNode* tmp = slow->next;
slow->next = tmp->next;
return dummyHead->next;
}
注意点: 1 fast应该移动N+1;2 最后应该dummy->head(这个节点一定存在),原head可能是NULL。
三、链表相交
链表相交的题目,一开始并没有理解到相交是什么意思,后面看了代码随想录和code,明白是指针相等,一旦存储节点的地址相等,说明相交,记住这一点,这个题目就清晰了。
首先对齐两个链表,从右往左对齐。然后依次遍历,当listNode A = B,返回该节点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
int lenA = 0;
int lenB = 0;
struct ListNode* curA = headA;
struct ListNode* curB = headB;
while(curA)
{
lenA++;
curA = curA->next;
}
while(curB)
{
lenB++;
curB = curB->next;
}
int step = lenA > lenB ? lenA - lenB: lenB - lenA;
int flg = 0;
flg = lenA > lenB? 0 : 1;//A>B 0 A<=B 1
curA = headA;
curB = headB;
while(step--)
{
if(flg == 0)
{
curA = curA->next;
}
else
{
curB = curB->next;
}
}
while(curA || curB)
{
if(curA == curB)
{
return curA ;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
四、环形链表II
根据代码随想录的讲解(链接:代码随想录),主要是需要理解到环形链表相遇时候的公式推导,分为两个部分:1 两个节点相遇时候的节点位置;2 推导环形入口点的公式;
struct ListNode *detectCycle(struct ListNode *head) {
//slow走一步 fast走2步,直到fast结束
struct ListNode * slow = head;
struct ListNode * fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
/**第一次两个节点相遇,从该点开始,一直遍历,直到两点相等就是入口**/
struct ListNode* indx1 = slow;
struct ListNode* indx2 = head;
while(indx1 != indx2)
{
indx1 = indx1->next;
indx2 = indx2->next;
}
return indx2;
}
}
return NULL;
}