[快慢指针]19 - 删除链表的倒数第N个节点 - python + Java

58 阅读2分钟

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

示例:

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

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

说明:给定的 n 保证是有效的。
进阶:你能尝试使用一趟扫描实现吗?


如果不要求使用一趟扫描就实现结点的删除,暴力的方法可以先读取链表中所有的结点到数组中,然后再移除数组中倒数第n个值,最后使用数组再建立新的链表即可。但是这样的方式相当于需要扫描两次链表。

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        if head == None: return None
        if head.next == None and n == 1: return None

        l =0
        cur = head
        while cur:
            l += 1
            cur = cur.next

        r = []
        cur = head
        while cur:
            r.append(cur.val)
            cur = cur.next

        r = r[: l - n] + r[l - n + 1:]
        newHead = ListNode(-1)
        cur = newHead
        for i in r:  
            node = ListNode(i)
            cur.next = node
            cur = cur.next

        return newHead.next

更好的方式是在扫描的过程中实现结点的删除,链表的倒数第n个结点即正数的第l - n个结点:

  • 如果 l - n == 0,则直接返回head.next即可

  • 否则,设置cur指向head,同时设置index寻找l - n - 1

    • 如果index == l - n - 1,则执行cur.next = cur.next.next,跳出循环返回head
    • 否则cur = cur.next, index += 1继续往后寻找
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        if head == None: return None
        if head.next == None and n == 1: return None
		# 获取链表长度
        p = head
        l = 0
        while p:
            l += 1
            p = p.next

        k = l - n
        if k == 0:
            head = head.next
            return head
        else:
            index = 0
            cur =  head
            while cur:
                # print(index, cur.val)
                if index == k - 1:
                    cur.next = cur.next.next
                    cur = cur.next
                    break
                cur = cur.next
                index += 1
            return head

链表问题同样可以尝试用双指针法进行解决,设置新节点链接到head前面,然后设置指针slowfast分别指向新链表的头结点。首先让fast多走n步,然后slowfast同时往后走,直到fast.next == None。此时slow所指向的节点是要删除结点的前驱结点,执行slow.next = slow.next.next,删除倒数第n个结点,返回h.next

AC code

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        if head == None: return None
        if head.next == None and n == 1: return None

        h = ListNode(0)
        h.next = head
        slow, fast = h, h

        for i in range(n):
            fast = fast.next
            
        while fast.next:
            fast = fast.next
            slow = slow.next
            
        slow.next = slow.next.next
        
        return h.next

Java解题代码:

/**
 * 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 slow = head;
        ListNode fast = head;

        // 先让快指针走n步
        while(n-- > 0){
            fast = fast.next;
        }

        // 判断一种特殊情况:如果此时fast == null,说明要删除的就是它
        // 直接返回head.next
        if(fast == null){
            return head.next;
        }

        // 否则快慢指针一起走
        while(fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }

        // fast走到头时,slow位于倒数第n + 1个节点处
        // 删除倒数第n个节点,slow.next = slow.next.next
        slow.next = slow.next.next;
        return head;
    }
}