LEETCODE之链表

74 阅读3分钟

链表题目的解决, 通常要结合画图来理解

876 链表的中间结点

入门级别, 快慢指针即可解决

var middleNode = function(head) {
    let quick = head,
        slow = head
    while (quick!==null && quick.next!==null) {
        quick = quick.next.next
        slow = slow.next
    }
    return slow
};

160 相交链表

让我用一道很浪漫的题开启大家的链表之旅吧!

关键词: 重走一遍你的路, 我们终究会相遇

function getIntersectionNode (headA, headB) {
    let pA = headA
    let pB = headB
    while (pA!==pB) {
        pA = (pA===null) ? headB : pA.next
        pB = (pB===null) ? headA : pB.next
    }
    return pA
}

206 反转链表

pre, cur, next三指针

本题目不使用dummy节点, 使用pre和cur双节点的方式, 由于单链表的限制, 额外使用一个next指针记录cur节点的下一个节点的位置, 每次遍历时, 让cur指向pre, 并让pre前移, cur前移(指向next)

/**
 * 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) {
    // pre始终落后cur和next一个身位, cur和next指向同一个节点
    let pre = null,
        cur = head,
        next = head
    while (cur!==null) {
        // 使用next指针记录cur后一位的地址
        next = cur.next
        cur.next = pre
        // pre前移一位
        pre = cur
        // cur前移一位
        cur = next
    }  
    return pre
};

利用es6的解构赋值, 我们有更为精巧的解法

var reverseList = function(head) {
    // pre始终落后cur一个身位, cur指向当前节点
    let pre = null,
        cur = head
    while (cur!==null) {
        // 利用es6的解构赋值, 你甚至不需要额外的next指针
        [cur.next, pre, cur] = [pre, cur, cur.next]
        // pre, cur移动的顺序也可以改变
        // [cur.next, cur, pre] = [pre, cur.next, cur]
    }  
    return pre
};

92 反转链表 II

pre, cur, next三指针 + 额外存储

想法:

  • 反转位置m到位置n之间的链表
  • 将原链表与反转后的链表拼接

步骤:

  • 初始化变量: pre指向前方, curr遍历当前链表, 二者依次增加, pre始终落后curr一个身位
  • 将pre, curr递增到位置m之前, 使用pre2和curr2分别存储当前pre和curr的位置
  • 反转位置m到位置n之间的链表
  • 利用pre2和curr2, 将反转后的部分链表与原链表拼接 image.png
var reverseBetween = function (head, m, n) {
  let prev = null;
  let curr = head;
  for (let i = 1; i < m; i++) {
    prev = curr;
    curr = curr.next;
  }

  let prev2 = prev;
  let curr2 = curr;

  for (let i = m; i <= n; i++) {
    [curr.next, prev, curr] = [prev, curr, curr.next];
  }
  if (m > 1) {
    prev2.next = prev;
  } else {
    head = prev;
  }
  curr2.next = curr;
  return head;
};

141 环形链表

快慢指针

  • 创建两个指针都指向头部, 快指针走两步, 慢指针走一步
  • 如果二者能相遇, 则为环形链表
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    if (head===null) return false
    let fast = head,
        slow = head
    while (fast.next!==null && fast.next.next!==null) {
        fast = fast.next.next
        slow = slow.next
        if (fast === slow) {
            return true
        }
    }
    return false
};

142 环形链表 II

原理图解: image.png 代码:

var detectCycle = function(head) {
    if (head===null) return null
    let fast = head,
        slow = head,
        isCircle = false
    while (fast.next!==null && fast.next.next!==null) {
        fast = fast.next.next
        slow = slow.next
        if (fast===slow) {
            // 此时说明有环, 退出循环
            fast = head
            isCircle = true
            break
        }
    }
    if (!isCircle) return null
    while (fast!==slow) {
        fast = fast.next
        slow = slow.next
    }
    return fast
};

328 奇偶链表

奇偶双指针

/**
 * 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 oddEvenList = function(head) {
    if (head===null) return null
    if (head.next===null) return head
    let odd = head
    let even = head.next,
        evenHead = even
    while (even!==null && even.next!==null) {
        odd.next = odd.next.next
        odd = odd.next
        even.next = even.next.next
        even = even.next
    }
    odd.next = evenHead
    return head
};