admin管理员组文章数量:1794759
LeetCode(C++)刷题计划:19
19-删除链表的倒数第N个节点
@Author:CSU张扬 @Email:csuzhangyang@gmail or csuzhangyang@qq
algorithms | Medium | 36.08% | linked-list / two-pointers | Unknown |
给定一个链表,删除链表的倒数第 n n n 个节点,并且返回链表的头结点。
示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链表变为 1->2->3->5.说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
来源:力扣(LeetCode) 链接:leetcode-cn/problems/remove-nth-node-from-end-of-list/
2. 解法:双指针法如何找到链表的倒数第 n n n 个节点?
需要注意的是,我们目的是要 删除 倒数第 n 个节点,所以我们要找到倒数第 n + 1 个节点。也就是步骤 2 中,l1 总共应该向右移动 n 次。
接下来,思考这么一个问题。 假如我们的链表长度为 n n n,而我们要删除倒数第 n n n 个元素(也就是第一个元素),这时会有什么问题呢?
答案很明显,我们无法找到倒数第 n + 1 n+1 n+1 个元素,也就是第0个元素,但是我们没有第0个元素,这时就无法删除第一个元素了。
有的人可能会说,那我们直接对这种情况特殊处理就好啦。 但是,需要注意的是,我们的复杂度要求是 只遍历一遍链表 ,也就是我们先前并不知道链表的长度,也就无法判断是否是这种情况。
在这里,我们给出两种解决办法。
2.1 解法一向头结点前增加一个结点,也就是添加了第0个元素。
注意一个问题。 最后返回的是 h->next,开头我们定义了 l1 = l2 = h, l1->next = head,即:h->next = head,那么能不能返回 head 呢? 答案是不能。 在删除的是第一个元素的情况下结果会出错,例如:
输入:[1,2,3,4,5] 5 输出:[1,2,3,4,5] 预期结果:[2,3,4,5]因为我们的目的是删除该头结点,我们并没有对 head 这个头结点有任何操作,那么最后返回 head 的话就必定会有头结点存在。
我们会在解法二中看到,处理删除第一个元素的情况是返回 head->next。
执行用时: 8 ms, 在所有 cpp 提交中击败了72.41%的用户 内存消耗: 8.6 MB, 在所有 cpp 提交中击败了76.23%的用户
/** * 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* l1 = new ListNode(-1); l1->next = head; ListNode* l2 = l1; ListNode* h = l2; for (auto i = 0; i < n; ++ i) { l1 = l1->next; } while (l1->next) { l1 = l1->next; l2 = l2->next; } l2->next = l2->next->next; return h->next; } }; 2.1 解法二参考【微笑永恒】
执行用时: 4 ms, 在所有 cpp 提交中击败了96.70%的用户 内存消耗: 8.4 MB, 在所有 cpp 提交中击败了90.51%的用户
/** * 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* l1 = head; ListNode* l2 = l1; // 右移n-1次 for (auto i = 0; i < n - 1; ++ i) { l1 = l1->next; } // 判断要删除的元素是不是第一个元素 if (!l1->next) return head->next; // 应该右移n次,补上一次 l1 = l1->next; // 两个指针同时移动,直到l1到末尾 while (l1->next) { l1 = l1->next; l2 = l2->next; } // 删除该元素 l2->next = l2->next->next; return head; } };版权声明:本文标题:LeetCode(C++)刷题计划:19 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686518586a76745.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论