LeetCode《初级算法》链表之删除链表的倒数第N个节点 -- JavaScript

909 阅读3分钟

题目

题目链接:leetcode-cn.com/leetbook/re…

image.png


题解

1、两次遍历删除给定节点

链表节点的删除,一般思路都是先找到要删除节点的前一个节点,然后再删除需要删除的节点;这里先遍历链表得到链表的长度,再遍历到自定节点的前一个节点来对给定节点进行删除;

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {

    let len = 0;
    let temp = head;

    // 获取链表长度
    while(temp !== null) {
        len++;
        temp = temp.next;
    }
    
    // 处理删除第一个节点的情况
    if(n === len) {
        return head.next;
    }

    // 找到指定位置节点的前一个节点,并将指定节点删除
    len = len - n;
    temp = head;
    for(let i = 2;i <= len;i++) {

        temp = temp.next;
    }

    temp.next = temp.next.next; // js 中自动回收内存,只要将指向对象的引用去掉就行;

    return head;
};

注意边界条件,当要删除第一个节点时因为链表没有头节点,使得和删除其它节点的操作并不一致,因此要对删除第一个节点做额外操作;

2、使用一次遍历删除指定节点

空间换时间是普遍规律;

如果想要一次遍历就将指定节点给删除,我们可以通过先使用数组将所有节点的地址存下来;

然后利用顺序存储的数组的随机访问直接获得指定节点的前一个节点;

最后对指定节点进行删除;


/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {

    let len = 0;
    let temp = head;

    let addressArr = [];

    while(temp !== null) {

        len++;
        addressArr.push(temp);
        temp = temp.next;
    }

    // 处理删除第一个节点的情况
    if(n === len) {
        return head.next;
    }

    addressArr[len - n - 1].next = addressArr[len - n].next;
    addressArr = null;

    return head;
};

3、使用递归实现

也可以使用递归实现,退出递归栈的过程计数,这样就可以实现倒数计数对指定节点进行删除; 要注意对当需要删除的节点是第一个节点时的处理;

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
    // 这个标志用来处理当删除的节点是第一个节点时,便于后面对其进行处理
    let flag = false;

    function deleteNode(initialHead,head,n) {

        if(head === null){
            return n;
        }

        m = deleteNode(initialHead,head.next,n);

        if(m === 0) {
            head.next = head.next.next;
        }else if(m === 1 && head === initialHead) {  // 当要删除的节点是最后一个节点
           
            flag = true; 
            return ;
        }
        
        
        return m -1;
    }

    deleteNode(head,head,n); // 在写js的时候经常会这样,定义了函数忘了执行...

    if(flag) {
        head = head.next;
    }

    return head;
};

4、给链表添加上头节点以统一操作

链表没有头节点带来删除操作的不一致,因此先给链表节点加上一个头节点,然后再使用上面的方法处理链表;

以下是先给链表加上头节点,然后再两次遍历删除节点的代码:

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {

    const vhead = new ListNode(null,head);

    let len = 0;
    let temp = head;

    // 获取链表长度
    while(temp !== null) {
        len++;
        temp = temp.next;
    }
    

    // 找到指定位置节点的前一个节点,并将指定节点删除
    len = len - n;
    temp = vhead;
    for(let i = 1;i <= len;i++) {

        temp = temp.next;
    }

    temp.next = temp.next.next; // js 中自动回收内存,只要将指向对象的引用去掉就行;


    return vhead.next;
};



大家如果有更好的思路和解法,欢迎大家一起来讨论啊~

这是使用 JavaScript 对 LeetCode《初级算法》的每道题的总结和实现的其中一篇,汇总篇在这里:

juejin.cn/post/700669…