前端算法 (19)

57 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

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

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

解题思路

思路一

我们使用双指针的方式进行解决,首先进行处理一下边界的情况,在定义双指针,左侧指针和右侧指针间隔n,左侧的指针下个元素就是我们所要删除的,在定义一个index变量,用户记录rightPointer走的次数,便于赋值左侧指针

var removeNthFromEnd = function (head, n) {
    if(!head){return head}
    if(!head.next && n ===1){return null}
    let rightPointer = head 
    let leftPointer = null
    let index = 0 
    while (rightPointer) {
        //右侧指针走到了末尾
        if (!rightPointer.next) {
            //左侧指针再循环一次就是要删除的元素了,因此要删除的元素是head节点
            if((n - index) === 1 ){
                if(!leftPointer){
                    return head.next
                }
            }else {
                //左侧指针的下一个就是要删除的元素,并删除
                leftPointer.next = leftPointer.next.next
            }
        }
        //右侧指针不断向右移动
        rightPointer = rightPointer.next
        //记住移动次数
        index++
        //移动n次后左侧指针开始指向头指针
        if (index === n) {
            leftPointer = head
        }else {
            //随着右侧指针移动,左侧指针也不断移动
            if (leftPointer) {
                leftPointer = leftPointer.next
            }
        }
    }
    //如果循环中没有返回,那么头指针就没有变,就返回原来的头指针
    return head
}

思路二

加个虚拟头结点,以防止溢出,比如只有5个节点,要求找到倒数第5个,即第一个,那么应该找到倒数第6个。 主程序中,先走的指针是从dummy开始的,找到倒数第N+1个节点

let findFromEnd = (head, n) => {
    let p1 = new ListNode;
    let p2 = new ListNode;
    p1 = head;
    for(let i = 0; i < n; i++) {
        p1 = p1.next; // 倒数第几个就先走几步
    }
    p2 = head;
    while(p1 !== null) {
        p2 = p2.next;
        p1 = p1.next;
    }
    return p2;
}
var removeNthFromEnd = function(head, n) {
    let dummy = new ListNode(-1);
    dummy.next  = head;
    let delP = findFromEnd(dummy, n+1); // 从dummy开始
    delP.next = delP.next.next;
    return dummy.next;
};