当前位置 博文首页 > 龚厂长的博客:leetcode-31. 下一个排列

    龚厂长的博客:leetcode-31. 下一个排列

    作者:[db:作者] 时间:2021-07-26 17:41

    题目:
    给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

    示例:
    给定一个链表: 1->2->3->4->5, 和 n = 2.

    当删除了倒数第二个节点后,链表变为 1->2->3->5.
    说明:

    给定的 n 保证是有效的。

    进阶:
    你能尝试使用一趟扫描实现吗?

    分析:
    不考虑进阶要求的话,这个题目很简单,要找倒数第n个节点,首先遍历一遍,找到链表的总长度length,然后length-n+1就是从链表头开始数要删除的节点了。然后再从头开始遍历找到length-n+1的节点删除即可。
    下面考虑一下进阶,使用一趟扫描。
    一趟扫描的话,我们考虑如下两个指针,一个指针用于遍历整个链表,另一个指针在遍历链表的过程中使用与第一个指针保持距离为n,也就是两者之间始终保持有n-1个节点,这样当第一个节点遍历到链表尾的时候,第二个指针指的位置正好是倒数第n个节点。这样使用一遍遍历便可以找到要删除的第n个节点了,但是还有一个问题,要删除第n个节点,需要知道这个节点的前一个节点,因此可以增加第三个指针,这个指针始终指向第二个指针指向的节点的前一个节点。
    上面这个算法使用了三个指针,那么使用两个指针是否可行?答案是可行的,第一个指针还是用于遍历整个链表,第二个指针指向的节点始终与第一个指针指向的节点之间保存n个节点,这样第一个指针遍历到链表尾的时候,第二个指针指向的节点正是要删除节点的前一个节点。
    代码如下:

    public ListNode removeNthFromEnd(ListNode head, int n) {
            ListNode preNthNode=null;//倒数第n节点的前一个节点
            ListNode t=head;//遍历指针,用于遍历一遍链表
    
            while(t.next!=null){
                t=t.next;//切换下一个节点
                n--;
                if(n==0){
                    preNthNode=head;
                }else if(n<0){
                    preNthNode=preNthNode.next;
                }
            }
            //如果preNthNode=null,表示要删除的是链表的第一个节点
            if(preNthNode==null){
                head=head.next;//删除第一个节点
            }else{
                preNthNode.next=preNthNode.next.next;
            }
            return head;
        }
    

    运行结果:
    在这里插入图片描述

    cs