203.移除链表元素
题目:
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
思路:
没有思路。
代码:
写不出来。
优化:
其实不是不会写,只是对于js中的链表的声明方式和使用不熟练。对于链表倒是理解,但是对于js中实现链表的类方法,还有输出头节点会输出整个链表的值有点难以理解,后来多次debug输出各种next和val之后,逐渐明白:头节点是一个指针,如果要输头数头节点的值要使用类方法里定义的.val方法,如果直接对节点进行输出,那么会默认输出节点包括节点之后的链表的值。
代码:
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var removeElements = function(head, val) {
const dummyNode = new ListNode(-1,head)
let cur = dummyNode
while (cur.next) {
if (cur.next.val===val){
cur.next = cur.next.next
continue
}
cur = cur.next
}
return dummyNode.next
};
总结:
这道题虽然很简单,但是因为自己对js中链表的使用不熟悉没有独立完成,但是没关系,因为我现在已经明白js中链表是怎么回事了。
707.设计链表
题目:
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。
如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList 类:
MyLinkedList()初始化MyLinkedList对象。int get(int index)获取链表中下标为index的节点的值。如果下标无效,则返回-1。void addAtHead(int val)将一个值为val的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)将一个值为val的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)将一个值为val的节点插入到链表中下标为index的节点之前。如果index等于链表的长度,那么该节点会被追加到链表的末尾。如果index比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)如果下标有效,则删除链表中下标为index的节点。
思路:
没有思路。
代码:
写不出来。
优化:
看了解题步骤,说一下现在的思路:
- 首先声明一个链表类
- 声明一个构造函数链表,设置属性size表示链表长度为0,head表示头节点、tail表示尾节点指向空
- 声明一个获取节点的方法getNode,在这个方法中声明一个链表,设置一个虚拟头节点0指向原来链表的头节点,将链表原来的每个节点依次遍历,重新设置下标后,返回新的链表
- 声明获取节点的方法get,传入参数index
- 判断index是否有效,无效返回-1
- 有效就调用getNode方法,传入参数index,返回在getNode方法中查找到的index的值
- 声明添加头节点的方法addAtHead,传入参数val
- 声明一个新的链表,将val指向原来的头节点,然后将头指针指向新的链表,将链表长度size+1
- 此外,判断是否有尾节点如果没有,则该链表为空,尾节点也就是头节点,直接赋值
- 声明添加尾节点的方法addAtTail,传入参数val
- 声明一个新的链表,将val指向null,将链表长度size+1
- 判断是否存在尾节点
- 如果存在,将原来的尾节点指向新的链表,将尾指针更新为指向新链表的val值,然后返回
- 如果不存在直接将头尾节点全部更新为新的链表
- 声明添加特定位置值的方法addAtIndex,传入参数index、val。
- 首先判断如果index为链表长度,那么直接调用addAtTail方法,传入参数val,将val添加到节点尾部;
- 判断index如果小于等于0,调用addAtHead方法,传入参数val,将val添加到节点头部;
- 判断index如果大于链表长度,直接返回。
- 如果以上条件都不满足,声明一个节点值node,因为要在index之前添加元素,调用getNode方法传入参数index-1,获取要添加元素的位置,然后将node.next指向一个新的链表,该链表头节点为val,val指向node.next,最后链表长度size+1
- 声明删除特定位置值的方法delateAtIndex,传入参数index
- 首先判断index是否有效,无效直接返回。
- 判断index是否为0
- 如果为0,则删除头节点,同时判断index是否为链表长度-1,如果是说明该链表只有一个元素,同时删除尾节点,然后链表长度size-1,直接返回。
- 如果index不为0,声明一个节点值node,调用getNode方法获取index-1(要删除的节点的前一个节点),直接将node.next指向node.next.next
- 最后判断index是否为尾链表长度-1(是否为尾节点),如果是将尾节点指针更新为node,链表长度size-1
代码:
class LinkNode {
constructor(val,next) {
this.val = val
this.next = next
}
};
var MyLinkedList = function() {
this.size = 0
this.head = null
this.tail = null
};
// 虚拟头节点
/**
* @param {number} index
* @return {number}
*/
MyLinkedList.prototype.getNode = function(index) {
if (index < 0 || index >= this.size) return null
let dummyNode = new LinkNode(0,this.head)
while (index-- >= 0) {
dummyNode = dummyNode.next
}
return dummyNode
};
/**
* @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) {
const node = new LinkNode(val,this.head)
this.head = node
this.size++
if (!this.tail) {
this.tail = node
}
};
/**
* @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
};
/**
* @param {number} index
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtIndex = function(index, val) {
if (index > this.size) return
if (index === this.size) {
this.addAtTail(val)
return
}
if (index <= 0) {
this.addAtHead(val)
return
}
const node = this.getNode(index-1)
node.next = new LinkNode(val,node.next)
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 (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--
};
总结:
这道题很复杂,我本来以为自己做了第一题理解了链表就没事了,没想到人看傻了,没办法,只能看着题解慢慢理解,然后多刷几遍,把这个变成自己的东西
206.反转链表
题目:
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
思路:
没有。
代码:
不会。
优化:
看了题解,两种解法——双指针、递归,这两种解法用图示非常容易理解,但是光看代码有点绕,下面给出优化后思路:
- 双指针:设置两个指针prev、cur,prev指向null,cur指向head,设置一个临时值tmp,设置一个循环,判断条件为cur,如果cur一直向后遍历指到null结束循环,循环中的操作为:
- 将cur.next赋值给tmp
- 将prev赋值给cur.next
- 将cur赋值给prev
- 将tmp(cur.next)赋值给cur
- 递归:设置一个函数,传入prev、cur两个参数,函数内部首先判断cur是否为null,如果是直接返回prev,也就是prev和cur都遍历到链表末尾的情况。具体操作:
- 设置一个临时值tmp,将cur.next赋值给tmp
- 将prev赋值给cur.next
- 此时cur作为下一次操作的prev,tmp(cur.next)作为下一次操作的cur,调用函数本身,传入参数cur、tmp
代码:
// 双指针
const reverseList = (head) => {
let tmp,cur = head,prev=null
while (cur) {
tmp = cur.next
cur.next = prev
prev = cur
cur = tmp
}
return prev
}
// 递归
const reverseList = (head) => {
return reverse(null,head)
}
const reverse = (prev,cur) => {
if (!cur) return prev
let tmp = cur.next
cur.next = prev
return reverse(cur,tmp)
}
总结:
我是菜狗。
Day3总结
今天初次尝试链表,之前使用js做前端开发的时候很少用到这个概念,完成了今天的任务以后也算初步掌握了js对链表操作的知识,但是也深深感觉自己的菜,希望自己继续努力。