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

本文详细介绍了链表的数据结构、不同类型的链表(单链表、双链表和循环链表),以及链表的存储方式和节点定义。重点探讨了移除链表元素的方法,包括原始方式和使用虚拟节点的实现,并涉及链表操作的练习,如设计链表并实现反转链表功能。
摘要由CSDN通过智能技术生成

链表:链表是通过指针串联在一起的线性结构,每个节点有两部分构成(数据域和指针域), 入口节点为 head,最后一个节点指向 null, 有单链表、双链表和循环链表这几种形式。

单链表:指针域只能指向下一个节点;

双链表: 指针一个指向下一个节点,一个指向上一个节点

循环链表: 头尾相连的链表

链表的存储方式: 链表的节点是散乱分布在内存中的某地址上;

链表节点的定义方式:

class ListNode {
    val;
    next = null;
    constructor(value) {
        this.val = value;
        this.next = null
    }
}

203.移除链表元素

我的思路: 需要判断每一个节点的next的值是否等于这个整数,如果等于整数的话,则将这个节点的指针指向next.next;那么如果 head 节点的值 === val, 应该如何识别,这时候需要一个虚拟节点的概念(dummy.next = head)

卡哥实现思路有两种方式:不设虚拟头节点,判断当前节点是否是头节点;设置虚拟头节点,用统一的方式来移除元素;

使用原始方式去移除元素要注意的点:需要判断头节点是否需要删除,

使用虚拟节点的方式来遍历需要注意:1)要建立临时变量来遍历这个链表,不能用头节点进行遍历,如果用头节点进行遍历,头节点指向的值在不断的改变,最后无法返回原先的头节点 2)如果 current.next是要删的元素,那么不需要将 current 指向下一个节点,因为这时还是需要判断 current.next是否=== val

原始的删除操作:

while(head && head.val === val) {
        head = head.next
    }
    if(head === null) return head
    let cur = head
    while(cur.next) {
        if(cur.next.val === val) {
            cur.next = cur.next.next
            continue
        }
        cur = cur.next
    }
    return head

使用虚拟节点的实现代码: 

var removeElements = function (head, val) {
    let dummy = new ListNode(0, head)
    dummy.next = head
    let current = dummy

    while (current.next) {
        if (current.next.val === val) {
            current.next = current.next.next
        } else {
            current = current.next

        }
    }

    return dummy.next
};

707.设计链表

这是一道练习链表操作的题

1. 初始化 linkedList对象

需要定义头节点、尾节点和 size

2, get value of given index from LinkedList

思路:for循环遍历链表,直至找到最后一个节点,即index 所对应的值;这里也用到了虚拟头节点的概念

3. 添加节点在头部

新的头节点 = 定义的val 和指向之前 head 的节点;

注意点: size 要增加;还有链表为空的情况

4. 添加节点在尾部

将当前尾部节点的指针指向需要添加的节点,并将尾部节点定义为添加的节点

5. 添加节点在指定的 index

将 index-1 的节点的 next 指向需要添加的节点,需要添加的节点的 next 指向当前链表 index 对应的节点

6.删除指定 index 的节点

将当前 index-1节点指向 index + 1的节点,注意这里要考虑所有的边界条件,并且 size 要做对应的变化

class ListNode {
    constructor(val, next) {
        this.val = val;
        this.next = next;
    }
}

var MyLinkedList = function () {
    this._head = null
    this._size = 0
    this._tail = null
};

MyLinkedList.prototype.getNode = function (index) {
    if (index < 0 || index >= this._size) return null
    let current = this._head //这个应该返回 head 节点本身
    for (let i = 0; i < index; i = i + 1) {
        current = current.next
    }
    return current
}
/** 
 * @param {number} index
 * @return {number}
 */
MyLinkedList.prototype.get = function (index) {
    if (index < 0 || index >= this._size) return -1
    return this.getNode(index).val
};

/** 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtHead = function (val) {
    let current = new ListNode(val, this._head) // 这里已经定义 next 指向之前的 head 了
    this._head = current
    if (!this._tail) {
        this._tail = current
    }
    this._size++
};

/** 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtTail = function (val) {
    let current = new ListNode(val, null)
    this._size++
    if (this._tail) {
        this._tail.next = current
        this._tail = current
        return;
    }
    this._tail = current
    this._head = current
};

/** 
 * @param {number} index 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtIndex = function (index, val) {
    if (index > this._size) return //如果等于链表 size,应该放在链表末尾
    if (index <= 0) {
        this.addAtHead(val)
        return
    }
    if (index === this._size) {
        this.addAtTail(val)
        return
    }
    const previous = this.getNode(index - 1)
    const node = new ListNode(val, previous.next)
    previous.next = node
    this._size++
};
/** 
 * @param {number} index
 * @return {void}
 */
MyLinkedList.prototype.deleteAtIndex = function (index) {
    if (index < 0 || index >= this._size) return
    if (index === 0) {
        this._head = this._head.next;
        if (!this._head) {
            this._tail = null
        }
        this._size--;
        return
    }
    const pre = this.getNode(index - 1)
    pre.next = pre.next.next
    if (!pre.next) {
        this._tail = pre
    }
    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.反转链表

思路: 将下一个节点的指针指向当前节点

 有几个注意点: 

1)改变的是 cur.next, 但是改变下一个节点又要获取未改变的 cur.next所以要暂存一下这个节点, cur到下一个节点 cur=temp

2)头节点要变成最后一个节点,所以要进行暂存,最后返回头节点

3)尾节点指向 null, 不断更新 pre, 

var reverseList = function(head) {
   let cur = head, temp = null, pre = null;

   while(cur) {
       temp = cur.next
       cur.next = pre //尾节点指向 null, 更新 pre, 以更新当前节点指针指向
       pre = cur
       cur = temp
   }
   return pre
};

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值