LeetCode-Remove Nth Node From End of List的一种算法
题目链接:https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/
Given a linked list, remove the n-th node from the end of list and return its head.
Example:
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
Note:
Given n will always be valid.
由题意可知,本次题目要求我们删除链表的倒数第n个节点,一般思路就是得到节点长度,然后减去n-1,找到删去节点的位置,在将其删去即可。
需要注意的是该节点可能是第一个节点,也可能是最后一个节点,这时操作又会有所不同。
于是这次也给出一个更加高效的算法,通过同时使用两个指针遍历链表,两个指针相差n个节点,如此一来当先遍历的节点遍历完整个链表,后遍历的节点就会指向倒数第n个节点。
一般算法如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if (head->next == NULL) { //判断只有一个节点的情况
return n==1?NULL:head;
}
ListNode* l = head, *l1 = head, *l2 = head->next;
int i = 0;
while (l->next != NULL) { //计算从头结点和尾节点的间隔
l = l->next;
i++; //当有5个节点时,i为4;
}
int flag = i-n; //判断删除的是否是头结点的标志
l = l1;
//遍历到待删除的节点,l2指向该结点,l1指向上一节点
for (int j = 0; j < i-n; j++) {
l1 = l1->next;
l2 = l2->next;
}
//当flag=-1,代表i+1=n,而i+1又为整个链表长度,故此时要删除的是头结点
if (flag == -1) {
return l2; //由于此时i-n=-1,没有进行上面的for循环,l2指向第二节点
}
//当l2既不指向是头结点,也不指向尾节点时的删减操作
if (l2->next != NULL) {
l2 = l2->next;
delete l1->next;
l1->next = l2;
return l;
}
//当l2是尾节点时的删减操作。
else {
delete l2;
l1->next = NULL;
return l;
}
}
};
高效算法如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *l = head, *l1 = head, *l2 = head, *temp;
//先让l2进行n次遍历
while (n > 0) {
l2 = l2->next;
n--;
}
//若此时l2为空,即l2指向尾节点的next的空节点,此时判断出删除的是头结点
if (l2 == NULL) {
return l->next;
}
//若非删除头结点,则开始令第二个指针l1与l2同时遍历
while(l2 != NULL) {
temp = l1; //temp指向l1的上一节点
l1 = l1->next; //l1指向待删除节点
l2 = l2->next;
}
//进行删除操作
temp->next = l1->next;
l1->next = NULL;
return l;
}