[路飞_js算法:环形链表 II 反转链表 反转链表 II 删除链表的倒数第 N 个结点 删除排序链表中的重复元素 删除排序链表中的重复元素 II]

162 阅读5分钟

环形链表 II

问题描述: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。(by leetcode 142)

​ 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos-1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

img

思路: 设置快慢指针,慢指针每次走一步,快指针每次走两步,若相遇,则说明有环,反之没有坏。有环的情况下,将慢指针重新指向头节点,快慢指针依次走一步,他们相遇的节点便是环开始的节点。

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
//注意事项:慢指针初始走一步,快指针初始走两步。
var detectCycle = function(head) {
    if(head==null) return null;
    let slow=head.next;
    let fast;
    if(head.next&&head.next.next){
    fast=head.next.next;
    }else{
        return null
    }
    while(fast!==null&&fast.next!==null&&fast!==slow){
        fast=fast.next.next;
        slow=slow.next;
    }
    if(fast===slow){
        slow=head;
        while(fast!==slow){
            fast=fast.next;
            slow=slow.next;
        }
        return slow
    }
    return null
};

反转链表

问题描述: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。(by leetcode 206

示例 1:

img

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

思路: 设置pre,cur指针,原本pre.next=cur;改变两个指针的方向(注意pre指针一开始是null,因为要切断head的next指向,所以pre需要设置为null.),并依次往后走。直到cur.next没有,说明走到倒数第二个节点,再改变两个指针的指向,此时返回当前cur则是反转后的链表头节点。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    if(head==null||head.next==null)return head;
    let pre=null;
    let cur=head;
    while(cur.next){
        let next=cur.next;
        cur.next=pre;
        pre=cur;
        cur=next
    }
    cur.next=pre
    return cur;
};

反转链表 II

问题描述: 给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。(by leetcode 92)

示例 1:

img

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

思路: 找到left节点前一个节点pre,将需要翻转链上的节点依次往前拿,让pre指向拿过来的节点,且拿过来的节点指向pre原本的下一个节点。直到将第right个节点也拿过来。由于头节点可能被改变,因此需要虚拟节点,返回虚拟节点下一个节点即可。

/**
 * 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} left
 * @param {number} right
 * @return {ListNode}
 */
var reverseBetween = function(head, left, right) {
    if(head==null||head.next==null) return head;
    let dummy=new ListNode();
    dummy.next=head;
    let pre=dummy;
    for(let i=0;i<left-1;i++){
        pre=pre.next;
    }
    let cur=pre.next;
    for(let i=0;i<right-left;i++){
        let next=cur.next;
        cur.next=next.next;
        next.next=pre.next;
        pre.next=next
       
    }
return dummy.next
};

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

问题描述: 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。(by leetcode 19)

示例 1:

img

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

思路: 先循环链表,算出链表长度,便可以找到倒数第N个节点,删除这个节点(记录当前要删除节点的前一个节点及后一个节点,直接指向即可,别忘了断开原本要删除节点的下一个指针),这里可能会删除头节点,因此需要用到虚拟节点。

/**
 * 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) {
    if(head==null)return head;
    let dummy=new ListNode()
    dummy.next=head;
    let cur=head;
    let num=0;
    while(cur){
        cur=cur.next;
        num++;
    }
let pre=dummy;
cur=dummy.next;
for(let i=0;i<num-n;i++){
    pre=pre.next;
    cur=cur.next;
}

pre.next=cur.next;
cur.next=null;
return dummy.next
};

删除排序链表中的重复元素

问题描述: 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次

返回同样按升序排列的结果链表。(by leetcode 83

示例 1:

img

输入:head = [1,1,2]
输出:[1,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
 * @return {ListNode}
 */
var deleteDuplicates = function(head) {
    if(head==null||head.next==null)return head;
    let dummy=new ListNode(0)
    dummy.next=head;
    let cur=head;
    while(cur!=null){
        let news=cur.next;
        while(news!==null&&cur.val==news.val){
             cur.next=news.next;
            news.next=null;
            news=cur.next
        }
         cur=cur.next;
    }
return dummy.next
};

删除排序链表中的重复元素 II

问题描述: 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。(by leetcode 82)

存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 **的数字。

返回同样按升序排列的结果链表。

示例 1:

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

返回同样按升序排列的结果链表。

  示例 1:

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

思路: 建立虚拟指针,指向head,向后遍历,一旦后两个节点相同,则记录该值,一直向后走,有跟该值一致的,则将该节点剔除,直到某一节点后面没有至少两个节点。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var deleteDuplicates = function(head) {
    if(head==null||head.next==null) return head;
 let dummy=new ListNode(0);
 dummy.next=head;
let cur=dummy;
while(cur.next&&cur.next.next){
    if(cur.next.val==cur.next.next.val){
        let temp=cur.next.val;
        while(cur.next&&cur.next.val==temp){
            cur.next=cur.next.next;
        }
    }
    else{
        cur=cur.next
    }
}
return dummy.next;
};