题目:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode) (leetcode-cn.com)
思路1:
设链表的长度为n,删除倒数第k个结点;倒数第k个节点即是第n-k+1个节点;
一般的思路是先遍历链表得到长度n,再找到第n-k+1个节点的前驱节点n-k,对其删除。需要对两个进行两次遍历
思路二:
只用一次遍历就可以找到前驱节点;
1.有两个指针p1和p2平且都指向头节点,先让p1走k步,剩下再走n-k步p1为空
2.此时让p2,p1以同样的速度走n-k步骤,此时p1为null,p2正好指向的是第n-k+1个节点,即要删除的节点
如果要找到前驱节点,只要使这里的k变成k+1即可:
方法函数如下:
public ListNode findPrevious(ListNode head,int k){ ListNode p1,p2; p1 = p2 = head; //p1先走k步 for(int i=0;i<k;i++){ p1 = p1.next; } // p1和p2走n-k步 while(p1!=null){ p1 = p1.next; p2 = p2.next; } //此时p2指向的节点为第n-k+1个节点 return p2; }
通过上面的函数可以找到前驱节点第n-k个节点,即倒数第k+1个节点
ListNode prev= findPrevious(head,n+1);
为了防止出现空指针的情况,比如说链表总共有 5 个节点,题目就让你删除倒数第 5 个节点,也就是第一个节点,那按照算法逻辑,应该首先找到倒数第 6 个节点。但第一个节点前面已经没有节点了,这就会出错。设置虚拟节点
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dumpy = new ListNode(-1); dumpy.next = head; // 找到第n-k个节点 ListNode prev= findPrevious(dumpy,n+1); //删除第n-k+1节点 prev.next = prev.next.next; return dumpy.next; } public ListNode findPrevious(ListNode head,int k){ ListNode p1,p2; p1 = p2 = head; //p1先走k步 for(int i=0;i<k;i++){ p1 = p1.next; } // p1和p2走n-k步 while(p1!=null){ p1 = p1.next; p2 = p2.next; } //此时p2指向的节点为第n-k+1个节点 return p2; } }