代码随想录算法训练营第三天 | 203. 移除链表元素、707. 设计链表、206. 反转链表

52 阅读1分钟

203. 移除链表元素

使用虚拟头结点,虚拟头结点是为了解决链表在头结点操作时和在其他节点操作时操作不同而用的

function removeElements(head: ListNode | null, val: number): ListNode | null {
  let newHead = null
  let cur: ListNode = {
    val: 0,
    next: head
  }
  while (cur) {
    if (cur.next && cur.next.val === val) {
      cur.next = cur.next.next
    } else {
      cur = cur.next
      if (!newHead) {
        newHead = cur
      }
    }
  }
  return newHead
};

707. 设计链表

双向链表,需要注意的是改动时当前节点的prev和next、prev节点的next、next节点的prev都需要改动

class LinkedNode {
  val: number
  prev: LinkedNode | null
  next: LinkedNode | null
}

class MyLinkedList {
  vHead: LinkedNode
  len: number = 0

  constructor() {
    this.vHead = { val: 0, prev: null, next: null }
  }

  print() {
    let cur = this.first()
    let s = ''
    while (cur) {
      s += (cur.val + '->')
      cur = cur.next
    }
    console.log(this.len + ',' + s)
  }

  first(): LinkedNode | null {
    return this.vHead.next
  }

  last(): LinkedNode | null {
    let last = this.first()
    while (last && last.next) {
      last = last.next
    }
    return last
  }

  getNode(index: number): LinkedNode | null {
    let cur = this.vHead
    for (let i = 0; i <= index; i++) {
      if (!cur) {
        break
      }
      cur = cur.next
    }
    return cur
  }

  get(index: number): number {
    const node = this.getNode(index)
    return node ? node.val : -1
  }

  addAtHead(val: number): void {
    const oldNode = this.vHead.next
    const newNode = { val, prev: this.vHead, next: oldNode }
    this.vHead.next = newNode
    if (oldNode) {
      oldNode.prev = newNode
    }
    this.len += 1
  }

  addAtTail(val: number): void {
    const last = this.last()
    if (last) {
      last.next = { val, prev: last, next: null }
      this.len += 1
    } else {
      this.addAtHead(val)
    }
  }

  addAtIndex(index: number, val: number): void {
    const node = this.getNode(index)
    if (index === this.len) {
      this.addAtTail(val)
    } else if (node && index < this.len) {
      const newNode = { val, prev: node.prev, next: node }
      if (node.prev) {
        node.prev.next = newNode
        node.prev = newNode
      }
      this.len += 1
    }
  }

  deleteAtIndex(index: number): void {
    const node = this.getNode(index)
    if (node) {
      if (node.prev) {
        node.prev.next = node.next
      }
      if (node.next) {
        node.next.prev = node.prev
      }
      this.len -= 1
    }
  }
}

206. 反转链表

双指针法:pre和cur两个指针同时移动,每移动一次就反转一次指向,最后pre移到尾结点也即新链表的头结点,注意每次tmp的保存

function reverseList(head: ListNode | null): ListNode | null {
  let cur = head
  let pre = null
  let tmp = null
  while (cur) {
    tmp = cur.next
    cur.next = pre
    pre = cur
    cur = tmp
  }
  return pre
};

递归法:每次递归里反转两个节点

function reverseList(head: ListNode | null): ListNode | null {
  return reverse(null, head)
};
function reverse(pre: ListNode | null, cur: ListNode | null) {
  if (!cur) {
    return pre
  }
  const tmp = cur.next
  cur.next = pre
  return reverse(cur, tmp)
}