[LeetCode19-链表-中等] 删除链表的倒数第N个节点
这道题也是关于链表的题目,题目原意是这样的,给你一个链表,删除这个链表的倒数第n个结点,并返回头结点(也就是其余的结点组成的新链表)
比如 1->3->5->7->9 n =2 也就是删除倒数第2个结点,值为7的结点。返回头结点为 1->3->5->9
关于链表的算法题,首先我们要知道链表解题经典三板斧: 哑巴结点(dummy node), 栈,快慢指针
针对这个题,我们首先想到的解法是什么,我们首先想到的是,我们先要找到要删除的倒数第n个结点的前一个结点,也就是倒是第n+1个结点,讲这个结点(倒数第n+1个结点)指针指向要删除结点(倒数第n个结点)的后继结点(倒数第n-1个结点). 从这个解释可以看到,它要找到要删除的这个结点的前一个结点,但是如果我们要删除的结点刚好是头结点呢(链表的第一个结点),那么它就没有前驱结点,这样我们需要对这种情况进行特殊处理。为了避免这种特殊处理的情况,我们通常会在头结点前面添加一个哑巴结点(dummy node), 等整个操作完成后,我们再把这个哑巴结点删除
有了方法论后,我们再回到这个问题本身,现在要删除链表的倒数第n个结点,我们来看个例子 1->3->5->7->9 删除倒数第2个结点(n=2) => 显然,我们需要找到这倒数第2个结点的位置,它处在这个链表的第4个位置,这个4是怎么得来的呢?
链表长度 5 - n (2) + 1 = 5 - 2 +1 = 4 ,所以我们要删除的结点就是位置在 (链表长度 - n + 1)的位置的结点,也就是顺序第 (链表长度 - n + 1)个结点,我们把这个结点删除后,把它的前驱结点 ((链表长度 - n + 1 - 1) 指向它的后驱结点 (链表长度 - n + 1 + 1), 整个工作就完成了
所以,现在问题很简单, 就变成找到链表长度,显然需要从头结点开始遍历整个链表,得到链表长度L。 =》 因为我们在头部加了一个哑巴结点,所以整个链表的长度变为 (L + 1), 要删除的结点位置变为 (L + 1 - N + 1)
C#代码如下:
public class ListNode { public int val; public ListNode next; public ListNode(int x = 0, ListNode nextNode = null) { val = x; next = nextNode; } } public ListNode RemoveNthFromEnd(ListNode head, int n) { //获取ListNode的长度 var L = 0; while (head != null) { ++L; head = head.next; } //在当前链表的头部添加一个哑巴结点 var dummyNode = new ListNode(0, head); var currNode = dummyNode; //从哑巴结点开始遍历,把它赋给当前结点 for (var i = 1; i < (L - n + 1); i++) //从第一个结点(哑巴结点)开始遍历,遍历到currNode变成要删除结点的前驱结点 { currNode = currNode.next; } currNode.next = currNode.next.next; // currNode此时是要删除结点的前驱结点,把它的指向变成要删除结点的后驱结点,就完成了对要删除结点的删除 var newListNode = dummyNode.next; return newListNode; }