自学内容网 自学内容网

数据结构与算法之链表: LeetCode 19. 删除链表的倒数第 N 个结点 (Ts版)

删除链表的倒数第 N 个结点

描述

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

示例 1

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2

输入:head = [1], n = 1
输出:[]

示例 3

输入:head = [1,2], n = 1
输出:[1]

提示

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz
  • 进阶:你能尝试使用一趟扫描实现吗?

Typescript 版算法实现


1 ) 方案1: 计算链表长度

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
    // 创建一个虚拟头节点,简化边界情况处理
    const dummy = new ListNode(0, head);
    let length = getLength(head);
    let cur: ListNode | null = dummy;

    // 移动到要删除节点的前一个位置
    for (let i = 1; i < length - n + 1; ++i) {
        if (cur?.next) {
            cur = cur.next;
        } else {
            break;
        }
    }

    // 删除目标节点
    if (cur && cur.next) {
        cur.next = cur.next.next;
    }

    // 返回新的头节点
    return dummy.next;
}

function getLength(head: ListNode | null): number {
    let length = 0;
    while (head !== null) {
        ++length;
        head = head.next;
    }
    return length;
}

2 ) 方案2: 双while

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
  // let dummy = new ListNode(null,head)
  const dummy = {
    next:head
  }
  let slow = dummy
  let fast = dummy
  while(n--){
    fast = fast.next
  }
  while(fast.next){
    fast = fast.next
    slow = slow.next
  }
  slow.next = slow.next.next
  return dummy.next
};

3 ) 方案3:栈

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
    const nodes: ListNode[] = [];
    const dummy = new ListNode(0, head);
    let node: ListNode | null = dummy;

    // 收集所有节点到数组中
    while (node !== null) {
        nodes.push(node);
        node = node.next;
    }

    // 找到要删除节点的前一个节点
    const prev = nodes[nodes.length - 1 - n];

    // 删除目标节点
    if (prev.next !== null) {
        prev.next = prev.next.next;
    }

    // 返回新的头节点
    return dummy.next;
}

4 ) 方案4:双指针

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
    // 创建一个虚拟头节点,简化边界情况处理
    const dummy = new ListNode(0, head);
    let first: ListNode | null = head;
    let second: ListNode | null = dummy;

    // 移动 first 指针,使其领先 second 指针 n 步
    for (let i = 0; i < n && first !== null; ++i) {
        first = first.next;
    }

    // 同时移动 first 和 second 指针,直到 first 到达链表末尾
    while (first !== null) {
        first = first.next;
        if (second) second = second.next;
    }

    // 删除目标节点
    if (second && second.next) {
        second.next = second.next.next;
    }

    // 返回新的头节点
    return dummy.next;
}

原文地址:https://blog.csdn.net/Tyro_java/article/details/145093774

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!