力扣工作周刷题 - 19题 删除链表倒数第N个节点

2020.3.23

力扣刷题日常,原题:点击此处

考点:链表遍历,快慢指针

题解:

1.这道题是876题的升级版本,读者可以先做876题热身,也可以做完这题回去巩固快慢指针的知识。

2.删除链表的倒数第 n 个节点,很明显,我们肯定想要的是一次遍历的方法,而不是二次遍历。

3.思路一(我个人的思路):参照876题解法,快指针走n格,慢指针走n-1格,到最后快指针已经不能在走的时候,从慢指针的位置向后面一个一个的检查,哪个是倒数第n个节点。

这个方法存在表现很差的时候,比如:
假设一条很长很长的链表,要删除倒数第二个元素,那么到最后快指针肯定比慢指针多走了一倍,而慢指针要从链表中间向后检查,时间复杂度可能甚至超越二次遍历。因此,这道题的快慢指针不能用876题的做法。

4.思路二:打从一开始,快指针就设计在n+1的位置。

这样做,就可以保证每次快慢指针中间都夹着n个元素。

当快指针到null时,就是倒数第n个元素。

为了保证快指针一开始就可以设计在n+1的位置,设置哑结点(dummy)在头结点之前。

下面为代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
    	//哑结点
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;
        //到达n+1的位置
        for(int i = 0; i <= n;i++){
            fast = fast.next;
        }
        while(fast != null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummy.next;
    }
}

思路一的代码:
可以AC,我觉得时间复杂度以及到达O(n2)了,不推荐学习。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // System.out.println(head.val);用于测试头结点
        ListNode slow = head;
        ListNode fast = head;
        boolean flag = false;
        while(true){
            ListNode temp = fast;
            for(int i = 0; i <n ; i++){
                temp = temp.next;
                // 如果已经超出范围了,则退出
                if(temp == null){
                    flag = true;
                    break;
                }
            }
            if(flag){ break;}
            // 慢指针记录上一个快指针的位置
            slow = fast;
            // 快指针更新
            fast = temp;
        }
        // 如果快和慢指向同一个,说明删除头结点
        if(slow == fast){
            head = head.next;
            return head;
        }
        while(slow != null){
            ListNode temp = slow;
            for(int i = 0; i < n; i++){
                temp = temp.next;
            }
            if(temp.next == null){
                slow.next = slow.next.next;
                break;
            }
            slow = slow.next;
        }
        return head;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值