第五天
链表的中间节点
使用快慢指针,fast指针一次走两个节点slow一次走一个节点.当fast或fast->next 走到NULL时我们的slow也就到了中间节点位置
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* middleNode(struct ListNode* head) { if(head == NULL) { return NULL; } struct ListNode* fast = head; struct ListNode* slow = head; while(fast != NULL&&fast->next != NULL) { fast = fast->next->next; slow = slow->next; } return slow; }
删除链表的倒数第N个节点
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
思路一(自己写法)
先遍历一遍数组得到数组长度然后通过数组长度和n(倒数第几的值)值相减的循环来得到使我们得到倒数第几的地址并我们先记录他上一个节点的地址最后处理特殊情况即可.
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) { if(head == NULL) return NULL; struct ListNode* cur = head; int len = 0; while(cur != NULL) { cur = cur->next; len++; } cur = head; struct ListNode* prev = head; for(int i = 0;i < len-n;i++) { prev = cur;//记录上一个节点 cur = cur->next; } if(len == n)//解决删头节点问题 { struct ListNode* tmp = head; head = head->next; free(tmp); return head; } if(prev == cur)//解决只有一个节点问题 { free(cur); return NULL; } //正常情况 prev->next = cur->next; return head; }
官方解法可以避免if语句去处理特殊情况不过有一点点难理解.但是整体思路相同.
思路二(双指针)
双指针的思路其实也很简单通过两个指针先让快指针先走n个节点再让慢节点和快捷点一起走最终当快指针走到空时结束(注:我写的是fast->next==NULL时退出是为了让慢指针指向要删除的前一个节点方便我们后面的删除).
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* removeNthFromEnd(struct ListNode* head, int n) { struct ListNode* fast = head; struct ListNode* slow = head; //头结点本身就为空 if(head ==NULL) { return NULL; } //只有一个节点 if(head->next == NULL) { free(head); return NULL; } for(int i =0;i<n;i++)//fast先走n步 { fast = fast->next; } while(fast != NULL&&fast->next != NULL)//fast!=NULL是为了防止删头结点. { slow = slow->next; fast = fast->next; } //fast为空只能是删头结点的时候 if(fast == NULL) { struct ListNode* cur = head; head = head->next; free(cur); return head; } struct ListNode* tmp = slow->next; slow->next = tmp->next; free(tmp); return head; }