代码随想录day3| 203.移除链表元素 、707.设计链表、 206.反转链表

53 阅读2分钟

学习内容

链表的定义和类型

链表是通过指针串联在一起的线性结构,链表元素的存储是不连续的。链表的入口节点称为链表的头结点也就是head。

image.png

常见链表的类型:

  • 单链表 {val, next}
  • 双链表 {prev, val, next}
  • 循环链表 ,链表收尾相连 tail.next = head

习题总结

203.移除链表元素

虚拟头结点的问题

/**
 * 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} val
 * @return {ListNode}
 */
var removeElements = function (head, val) {
    // 这种情况当head.val === val时,没删除head
    // let node = head
    // 所以要假立一个新的空head

    const listHead = new ListNode(0)
    listHead.next = head
    let node = listHead

    while (node&&node.next) {
        if (node.next.val === val) {
            node.next = node.next.next
        } else {
            node = node.next
        }
    }
    return listHead.next
}

707.设计链表

js中不存在链表
可以通过数组或者对象模拟链表
数组有点偷懒

  • 使用对象模拟链表,设置head和tail指针,size属性
  • 时刻要考虑边界问题!!!注意更改指针指向


class LinkNode {
    constructor(val, next) {
        this.val = val === undefined ? '' : val
        this.next = next === undefined ? '' : next
    }
}
function MyLinkedList() {
    this._size = 0
    this._head = null
    this._tail = null
}
/** 
 * @param {number} index
 * @return {number}
 */
MyLinkedList.prototype.get = function (index) {
    if (index >= this._size || index < 0) return -1
    let node = this._head
    while (index > 0) {
        node = node.next
        index--
    }
    return node ? node.val : null
};

/** 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtHead = function (val) {
    const node = new LinkNode(val, this._head)
    this._size++
    this._head = node
    if (this._size === 1) {
        this._tail = node
    }
    return node
};

/** 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtTail = function (val) {
    const node = new LinkNode(val, null)
    if (this._tail) {
        this._tail.next = node
    } else {
        this._head = node
    }
     this._tail = node

    this._size++
    return this._head
};

/** 
 * @param {number} index 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtIndex = function (index, val) {
    if (index > this._size || index < 0) return -1
    if (index === this._size) {
        this.addAtTail(val)
    } else if (index === 0) {
        this.addAtHead(val)
    } else {
        let prevNode = this._head
        while (index > 1) {
            prevNode = prevNode.next
            index--
        }
        const node = new LinkNode(val, prevNode.next)
        prevNode.next = node
        this._size++
    }

    return this._head
};

/** 
 * @param {number} index
 * @return {void}
 */
MyLinkedList.prototype.deleteAtIndex = function (index) {
    if (index >= this._size || index < 0) return null
    this._size--
    if (this._size === 0) {
        this._head = null
        this._tail = null
    } else if(index === 0){
        this._head = this._head.next
    } else{
        let preNode = this._head
        while (index > 1) {
            preNode = preNode.next
            index--
        }
        if (preNode.next.next) {
            preNode.next = preNode.next.next
        } else {
            preNode.next = null
            this._tail = preNode
        }
    }

    return this._head
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * var obj = new MyLinkedList()
 * var param_1 = obj.get(index)
 * obj.addAtHead(val)
 * obj.addAtTail(val)
 * obj.addAtIndex(index,val)
 * obj.deleteAtIndex(index)
 */

206.反转链表

方法一:双指针法 prev 和 cur 一前一后

注意:最后返回的是pre,迭代到最后,cur是空

  • 把next节点存起来temp
  • 把当前节点的next指向prev
  • 把prev往前走 = cur
  • 把cur往前走 = temp
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let cur = head
    let prev = null
    while(cur){
        const temp = cur.next
        cur.next = prev
        prev = cur
        cur = temp
    }
    return prev
};

方法二:递归 思路:递归几乎和双指针一样,无非就是把while循环变成了递归调用,注意:递归调用记得返回

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    const reverse = (cur, prev)=>{
        if(!cur) return prev
        const temp = cur.next
        cur.next = prev
       return reverse(temp, cur)
    }
   return reverse(head,null)
};

链表初步总结:

  1. 循环使用while方便
  2. 虚拟头结点的使用
  3. 双指针翻转链表
  4. 尤其要注意边界问题
  5. 要总结class和function的区别