【leetcode】19. 删除链表的倒数第 N 个结点

题目: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;
   }

     
}

 

posted @ 2022-05-01 19:38  MintMin  阅读(29)  评论(0编辑  收藏  举报