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

34 阅读3分钟

203. 移除链表元素

题目链接

时间复杂度 O(n)   空间复杂度 O(1)

要求: 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

思路

采用虚拟头节点的方法,不需要单独处理头节点==val时的情况。 处理的是当前节点的后一个即cur.next,所以要判断的是cur.next!= null,如果存在cur.next.val == val,那么则移除cur.next节点,如图,链表中移除D节点是将其C节点的指针指向E节点,C.next = C.next.next

image.png

/**
 * @param {ListNode} head
 * @param {number} val
 * @return {ListNode}
 */
var removeElements = function(head, val) {
    let ret = new ListNode(0, head) //虚拟头节点
    let cur = ret
    while(cur.next!= null){
        if(cur.next.val == val){
            cur.next = cur.next.next
        }else{
            cur = cur.next
        }
    }
    return ret.next
};

707. 设计链表

题目链接

要求:在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

思路

还不熟练,找了很久的bug


var MyLinkedList = function() {
    this.head = new ListNode(0, null)
    this.size = 0
};

/** 
 * @param {number} index
 * @return {number}
 */
MyLinkedList.prototype.get = function(index) {
    if(index<0 || index>this.size-1){
        return -1
    }
    let cur = this.head.next
    while(index--){
        cur = cur.next
    }
    return cur.val
};

/** 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtHead = function(val) {
    this.addAtIndex(0, val)
};

/** 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtTail = function(val) {
    this.addAtIndex(this.size, val)
};

/** 
 * @param {number} index 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtIndex = function(index, val) {
    if(index >this.size) return 
    if(index < 0) index = 0
    let cur = this.head
    while(index--){
        cur = cur.next
    }
    let tmp = cur.next
    let node = new ListNode(val, tmp)
    cur.next = node
    this.size++
    console.log(this.head.next)
};

/** 
 * @param {number} index
 * @return {void}
 */
MyLinkedList.prototype.deleteAtIndex = function(index) {
    if(index < 0 || index >=this.size) return 
    let cur = this.head
    while(index--){
        cur = cur.next
    }
    cur.next = cur.next.next 
    this.size--
};

/**
 * 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. 反转链表

题目链接

要求:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

思路

1.双指针法

链表反转其实只需要修改next指针指向
首先定义一个pre指针,初始化为null,cur指针指向head;
然后就开始循环了,需先将cur.nexttmp指针保存,因为后面需要修改cur.next指针的指向;
cur.next指向pre,则是直接将链表的第一个节点反转;
继续向前移动precur,直到cur指向null,返回pre即可。

时间复杂度  O(n)   空间复杂度  O(1)

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let pre = null, cur = head
    while(cur != null){
        let tmp = cur.next
        cur.next = pre
        pre = cur
        cur = tmp
    }
    return pre
};

2.递归法

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverse = function(pre, cur) {
    if(!cur) return pre;
    const temp = cur.next;
    cur.next = pre;
    // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
    // pre = cur;
    // cur = temp;
    return reverse(cur, temp);
}

var reverseList = function(head) {
    return reverse(null, head);
};