链表
反转链表
反转一个单链表。
function reverseList(head: ListNode | null): ListNode | null {
  let pre: ListNode | null = null
  let current = head
  while (current) {
    const next = current.next
    current.next = pre
    pre = current
    current = next
  }
  return pre
}
复杂链表的复制
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
class Node {
  val: number
  next: Node | null = null
  random: Node | null = null
  
  constructor(val: number) {
    this.val = val
  }
}
function copyRandomList(head: Node | null): Node | null {
  if(!head) return null
  
  // 准备工作
  const newHead = new Node(head.val)
    let node = head
  let newNode = newHead
  const hashMap = new Map<Node, Node>([
    [node, newNode] // 初始化
  ])
  
  while(node.next) {
    newNode.next = new Node(node.next.val)
    node = node.next
    newNode = newNode.next
    hashMap.set(node, newNode)
  }
  
  // 复制完毕之后,指针还原,进行 random 复制
  node = head
  newNode = newHead
  
  while(node) {
    newNode.random = hashMap.get(node.random)
    node = node.next
    newNode = newNode.next
  }
  
  return newHead
}
合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
function mergeTwoLists(l1: ListNode | null, l2: ListNode | null): ListNode | null {
  if(!l1) return l2
  else if(!l2) return l1
  
  if(l1.val < l2.val) {
    l1.next = mergeTwoList(l1.next, l2)
    return l1
  } else {
    l2.next = mergeTwoList(l1, l2.next)
    return l2
  }
}
环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
function hasCycle(head: ListNode | null): boolean {
  while(head) {
    if(head.flag) return true
    head.flag = true
    head = head.next
  }
  return false
}
环形链表II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
function hasCycle(head: ListNode | null): ListNode | null {
  // 快慢指针都从头节点出发
  let slow = head
  let fast = head 
  
  while(fast) { // 如果空链表就直接退出去返回 null
    if(fast.next === null) return null // 如果快指针没有下一个节点,说明无环
    slow = slow.next
    fast = fast.next.next
    if(slow === fast) { // 首次相遇
      fast = head // 快指针回到头节点
      while(true) {
        if(slow === fast) { // 此时相遇,慢指针到达之前第一次相遇时快指针所在位置
          return slow
        }
        fast = fast.next // 首次相遇之后,快指针不再需要一次走两步
        slow = slow.next
      }
    }
  }
    return null
}
相交链表
编写一个程序,找到两个单链表相交的起始节点。
function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null {
  let h1 = headA
  let h2 = headB
  
  while(h1 !== h2) {
    h1 = h1 ? h1.next : headB
    h2 = h2 ? h2.next : headA
  }
  return h1
}