LeetCode 19. Remove Nth Node From End of List 解题报告
题目描述
Given a linked list, remove the nth node from the end of list and return its head.
示例
Example 1:
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.
注意事项
Given n will always be valid.
Try to do this in one pass..
解题思路
我的思路:
题目的意思是删除从尾部开始的第n个节点。由于题目说了要一次遍历完成删除的操作,所以最普通的两次遍历的解法就不细讲了。看完题目,很自然地就意识到是双指针的问题,设置两个指针pFirst,pSecond,先让pFirst走n步,然后同时移动pFirst和pSecond,当pFirst走到最后一个节点时,pSecond是待删除的节点的前一个节点,直接按照常规的节点删除操作删除pSecond的next节点就行。
需要注意的一个问题是要删除的节点刚好是头结点,比如list=[1], n=1。这种情况会在移动pFirst时遇到(好吧,其实是我提交之后程序崩溃了才发现有这个问题)。解决的方式就是直接在移动时判断pFirst是否为空指针,因为删除头结点情况中,pFirst会完整地走过整个list指向尾节点的下一个节点成了空指针,此时,删除第一个节点并返回以第二个节点开始的子链表就行,见下面的我的代码。
参考思路:
通过了之后看着自己的代码总觉得别扭,因为类似的删除节点语句出现了两次,所以看看其他人的代码是不是更加简洁优美。果然,大神们的实现就是厉害,核心的思想跟我一样就是用双指针去解,然而为了解决删除头结点的问题,他们是巧妙地先在头结点之前插入了一个辅助节点,从而确保了前面的指针走了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) {
ListNode *pFirst = head;
ListNode *pSecond = head;
ListNode *temp = nullptr;
for(int i = 0; i < n; i++) {
pFirst = pFirst->next;
if (pFirst == nullptr) {
temp = head;
head = head->next;
delete temp;
return head;
}
}
while (pFirst->next) {
pFirst = pFirst->next;
pSecond = pSecond->next;
}
temp = pSecond->next;
pSecond->next = temp->next;
delete temp;
return head;
}
};
参考代码:
/**
* 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)
return nullptr;
ListNode new_head(-1);
new_head.next = head;
ListNode *slow = &new_head, *fast = &new_head;
for (int i = 0; i < n; i++)
fast = fast->next;
while (fast->next) {
fast = fast->next;
slow = slow->next;
}
ListNode *to_be_deleted = slow->next;
slow->next = slow->next->next;
delete to_be_deleted;
return new_head.next;
}
};
总结
指针的题目都是要小心地处理,不然程序很容易出现崩溃,通过这道题感觉收获最大是学习到了在头结点填充一个辅助节点的方式,这种方式我甚少考虑到,以后遇到类似的题目得多注意往这方面想想。
由于忙着做其他课程的项目,所以刷题的进度落下了一些,接下来还会做一道题目,赶回进度,又忙又累,但还是要加油啦~