代码随想录算法营DAY3 | 203.移除链表元素 707.设计链表 206.反转链表

代码随想录算法营DAY3 | 203.移除链表元素 707.设计链表 206.反转链表

链表理论基础

讲解: 理论基础
要点:
1.链表类型:单链表,双链表,循环链表
2.链表储存:内存空间不连续
3.链表定义:js版本如下

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

4.链表操作:插入,删除,查询
Alt

203.移除链表元素

题目链接: 203.移除链表元素

思路:
1.虚拟头结点:由于可能删除头结点所以需要设置
2.若next的值相等,删除后跳出本次循环:因为需要检验新的next对象是否也等于val
3.若不相等,则cur移动到下一个节点继续检验cur.next

代码:

var removeElements = function(head, val) {
    const ret=new ListNode(0,head);//虚拟头结点,可以方便删除头结点
    let cur=ret;//注意这里的cur是一个链表节点
    while(cur.next){//这里的访问指针方式和CPP不同,cpp是->,而这里作为对象访问
        if(cur.next.val===val){
            cur.next=cur.next.next;
            continue;//需要检查更新后的cur.next的值是否还是等于val
        }
        cur=cur.next;//cur更新等于下一个节点
    }
    return ret.next;//返回头结点
};

问题:
1.代码里的MyLinkedList.prototype.getNode里的prototype什么意思?
2.get返回的是val还是node?
答:写了两个函数,一个返回node,一个返回val。返回node的函数方便后面其它函数调用。
复杂度分析:
时间复杂度:O(n)

707.设计链表

题目链接: 707. 设计链表
思路:
1.需要linknode类和mylinknode函数初始化一个链表
2.各种方法的实现,详见注释。注意定义了一个getnode函数方便后面调用。

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。这里调用getnode,getnode里用了虚拟头结点。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。注意空链表加节点时尾节点的处理,也要等于node。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。 同样注意空链表加节点时头结点的处理。
  • addAtIndex(index,val):在链表中的第index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。 根据题目先分类讨论,然后调用getnode获取index-1的节点。
  • deleteAtIndex(index):如果索引 index有效,则删除链表中的第 index 个节点。1.先讨论删除的是头结点的情况,也就是if(index === 0) ,这种情况下如果删除的同时是尾节点(删完变成空链表),那尾节点要等于头结点null。2.删除的不是头结点,调用getnode获取index-1的元素,然后改变next的值。同样注意删除尾节点的情况,尾节点需要变成index-1的节点。

代码:

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

/**
 * Initialize your data structure here.
 * 单链表 储存头尾节点 和 节点数量
 */
var MyLinkedList = function() {
    this._size = 0;
    this._tail = null;
    this._head = null;
};

/**
 * Get the value of the index-th node in the linked list. If the index is invalid, return -1. 
 * @param {number} index
 * @return {number}
 */
MyLinkedList.prototype.getNode = function(index) {
    if(index < 0 || index >= this._size) return null;
    // 创建虚拟头节点
    let cur = new LinkNode(0, this._head);
    // 0 -> head
    while(index-- >= 0) {
        cur = cur.next;
    }
    return cur;
};
MyLinkedList.prototype.get = function(index) {
    if(index < 0 || index >= this._size) return -1;
    // 获取当前节点
    return this.getNode(index).val;
};

/**
 * Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtHead = function(val) {
    const node = new LinkNode(val, this._head);
    this._head = node;
    this._size++;
    if(!this._tail) {
        this._tail = node;
    }
};

/**
 * Append a node of value val to the last element of the linked list. 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtTail = function(val) {
    const node = new LinkNode(val, null);
    this._size++;
    if(this._tail) {
        this._tail.next = node;
        this._tail = node;
        return;
    }
    this._tail = node;
    this._head = node;
};

/**
 * Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. 
 * @param {number} index 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtIndex = function(index, val) {
    if(index > this._size) return;
    if(index <= 0) {
        this.addAtHead(val);
        return;
    }
    if(index === this._size) {
        this.addAtTail(val);
        return;
    }
    // 获取目标节点的上一个的节点
    const node = this.getNode(index - 1);
    node.next = new LinkNode(val, node.next);
    this._size++;
};

/**
 * Delete the index-th node in the linked list, if the index is valid. 
 * @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(index === this._size - 1){
            this._tail = this._head
        }
        this._size--;
        return;
    }
    // 获取目标节点的上一个的节点
    const node = this.getNode(index - 1);    
    node.next = node.next.next;
    // 处理尾节点
    if(index === this._size - 1) {
        this._tail = node;
    }
    this._size--;
};

问题:
思路会,但其实自己写的代码debug了半天没de出来,对js语法不熟悉,不清楚js指针这块的定义和js类与对象的写法,有点囫囵吞枣乱七八糟,最后复制了题解通过了。

206.反转链表

题目链接: 206.反转链表

思路:
1.双指针,其实需要三个指针,pre,cur和temp分别记录三个节点。
2.递归。两个参数,每次递归更新pre和head,head.next更改前用temp记录。

代码:

// 双指针:
var reverseList = function(head) {
    if(!head || !head.next) return head;
    let temp = null, pre = null, cur = head;
    while(cur) {
        temp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = temp;
    }
    // temp = cur = null;
    return pre;
};

// 递归:
var reverse = function(pre, head) {
    if(!head) return pre;
    const temp = head.next;
    head.next = pre;
    pre = head
    return reverse(pre, temp);
}

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

复杂度分析:
时间复杂度:O(n)

感想总结

1.今天还是看了很多题解,三刷的时候对js语法熟悉,思路熟悉了应该就可以手撕了。
2.对js函数和指针不熟悉,今天打算全看一遍,解决刷题中的问题。
3.设计链表那个debug了半天也没弄好,明天一定要仔细学一学怎么打印日志,怎么本地运行调试debug。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值