(算法)快慢指针与多指针

121 阅读2分钟

快慢指针——删除链表的倒数第 N 个结点

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

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.  
当删除了倒数第二个结点后,链表变为 1->2->3->5.  
说明: 给定的 n 保证是有效的。

题解:

/** 
* @param {ListNode} head
* @param {number} n 
* @return {ListNode}
*/
const removeNthFromEnd = (head, n) => {
    //初始化头节点
    const dummy = new ListNode();
    dummy.next = head;
    
    //快慢指针
    let fast = dummy;
    let slow = dummy;
    
    // 快指针走n步,即为快指针走完后慢指针刚好落在需删除的前一个节点
    while(n !== 0){
        fast = fast.next;
        n--;
    }
    
    //快慢同时走
    while(fast.next){
        fast = fast.next;
        slow = slow.next;
    }
    
    //删除慢指针后的节点
    slow.next = slow.next.next;
    
    // 返回头节点
    return dummy.next;
}

规则:

用空间换时间,对关键信息进行提前记忆,用两个指针对差值实现了记忆**

多指针法——链表的反转

定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

示例:

输入: 1->2->3->4->5->NULL  
输出: 5->4->3->2->1->NULL

题解:

/** 
* @param {ListNode} head
* @return {ListNode} 
*/
const reverseList = (head) => {
    //初始化节点为null作为反转的尾节点
    let pre = null;
    //初始化头节点
    let cur = head;
    while(cur !== null){
        // 记录下一个节点
        let next = cur.next;
        // cur和next断开 cur反转
        cur.next = pre;
        //指针往前走
        pre = cur;
        cur = next;
    }
    
    return pre;
}

规则:

处理链表结点之间的指针关系,pre的结果为已反转的链表,cur与next节点断开,存储旧指针用于遍历

局部反转一个链表

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

示例:

说明: 1 ≤ m ≤ n ≤ 链表长度。
输入: 1->2->3->4->5->NULL, m = 2, n = 4  
输出: 1->4->3->2->5->NULL

题解:

/** 
* @param {ListNode} head
* @param {number} m
* @param {number} n
* @return {ListNode} 
*/
const reverseBetween = (head, m, n) => {
    let pre, cur, leftHead;
    const dummy = new ListNode();
    dummy.next = head;
    
    // 保存反转区间m-1的前驱节点
    let p = dummy;
    for(let i = 0; i < m - 1; i++){
        p = p.next;
    }
    leftHead = p;
    
    // 反转区间
    let start = leftHead.next;
    pre = start;
    cur = pre.next;
    for(let i = m; i < n; i++){
        let next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    // 连接反转后的第一个节点
    leftHead.next = pre;
    start.next = cur;
    
    //返回头指针
    return dummy.next;
}

规则:

利用指针进行缓存