写在前面
好久没有重新刷题了,最近突然觉得自己代码水平急速下降,别的东西做的多了,因而想来这里刷刷题目,希望回复一下手感。
题目描述
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
解题思考
刚开始做这道题的时候苦思冥想,怎么样能够一次遍历就找到倒数第n个节点呢?我始终觉得是不可能的。后来我发现一个指针确实不能完成这样的事情,那两个指针呢?两个指针中间相距的间隔为n,不就可以了吗?
说干就干,我当即创建了两个指针,一个指针ptr指向遍历过的最后一个节点,另一个指针delayN指向ptr的前n个节点。这样,我们就能直接通过delayN指针找到倒数第n个节点了!
然而,实际操作和理论的思索还是有一些区别的,因为我发现,由于要删除节点,我们需要锚定delayN在倒数n+1位置的节点,那么这时候会出现两种可能:
- 倒数第
n个节点实际上是头节点; - 倒数第
n个节点不是头节点。
例如:1->2->3这样一个链表,1和3之间的距离是2,如果n = 3那么delayN和ptr的距离就必须是n = 3,这显然是不可能的。想解决这个问题,那么两个指针之间的距离则会有两种可能:
- 指针间的距离是
n-1; - 指针间的距离是
n。
接下来的思路就清晰了,将ptr锚定到最后一个节点,并在ptr后移的时候判断指针之间的距离,如果distance = n,则两个指针同时后移,如果distance < n则只有ptr后移。这样做之所以成立是因为题目里告诉我们n必然有效,所以我可以放心大胆的移。
因为n必然有效,因此当ptr移到最后一个节点的时候,如果distance < n那必然是删除头节点,我们只需要返回头节点的后一个节点了,它有两种可能:
NULL(链表长度为1)head->next
如果distance = n,就正常删除delay->next,并返回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) {
ListNode* ptr = head;
ListNode* delayN = head;
int count = 0;
while(ptr->next != NULL){ // length > 1
if(count < n)
count++;
else
delayN = delayN->next;
ptr = ptr->next;
}
count == n ? delayN->next = delayN->next->next : head = head->next;
return head;
}
};
总结
最终结果:
执行用时:
0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:
6.1 MB, 在所有 C++ 提交中击败了100.00%的用户
代码比较简洁,因为我确实不太喜欢看到太多的if else分支条件语句,因此能用三目运算符的就用了。看起来舒服一点。
本文分享了一种高效删除链表倒数第N个节点的方法,利用双指针技巧,仅需一次遍历即可实现,显著提升了算法效率。文中详细解析了解题思路,附带C++代码实现及性能分析。
1614

被折叠的 条评论
为什么被折叠?



