代码随想录day03
链表的定义
function ListNode(val, next) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}
203.移除链表元素
思路–虚拟头节点
1.如果删除头节点是和其他节点的删除方式不用,所以可以采用虚拟的头节点
/**
* 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) {
let node = new ListNode(0,head) // 设置一个虚拟头结点
let cur = node //定义一个临时的指针来进行后续操作
while(cur.next !== null) {
if(cur.next.val === val) {
cur.next = cur.next.next
continue
}
cur = cur.next
}
return node.next
};
重点和收获
1.链表首要想好指针是怎么移动的,是否会移动会访问null即可。
2.因为空指针的错误其实大多是一些if,while中不小心取到了空和循环次数和条件有关这种可以设计简单case比如1-2-3-null这种手动画图走一遍自己的代码就解决了。
3.虚拟头结点的主要目的是为了避免对头结点的特殊处理;这个处理就指的是修改操作。所以可以这样:涉及到对链表修改(如插入,删除,移动)的,都加个dummy,只是遍历取点就可以不用加
707设计链表
代码
class ListNode {
constructor(val, next) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}
}
var MyLinkedList = function() {
this.size = 0
this.head = null
this.dummy = new ListNode(0,this.head) // 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点
};
/**
* @param {number} index
* @return {number}
*/
MyLinkedList.prototype.get = function(index) {
if(index<0 || index>this.size-1) return -1
let cur = this.dummy.next
while(index--) { // 如果--index 就会陷入死循环
cur = cur.next
}
return cur.val
};
/**
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtHead = function(val) {
let node = new ListNode(val,this.head)
this.dummy.next = node
this.size++
};
/**
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtTail = function(val) {
let node = new ListNode(val,null)
let cur = this.dummy
while(cur.next) {
cur = cur.next //一直遍历找到尾部节点
}
cur.next = node
};
/**
* @param {number} index
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtIndex = function(index, val) {
let node = new ListNode(val,null)
let cur = this.dummy
if(index<0 || index>this.size-1) return
while(index--) {
cur = cur.next
}
node.next = cur.next
cur.next = node
this.size++
};
/**
* @param {number} index
* @return {void}
*/
MyLinkedList.prototype.deleteAtIndex = function(index) {
if(index<0 || index>this.size-1) return
let cur = this.dummy
while(index--) {
cur = cur.next
}
cur.next = cur.next.next
this.size--
};
206翻转列表
思路-双指针
1.首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。
2.注意 需要一个临时的指针,在cur.next还没赋值的时候提前保存下来,方便后面的使用
代码
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
//有两种方法
//双指针方法
var reverseList = function(head) {
let pre = null
let cur = head
let temp
while(cur) {
// 需要一个临时的指针,在cur.next还没赋值的时候提前保存下来,方便后面的使用
temp = cur.next
cur.next = pre
pre = cur
cur = temp
}
return pre
};
收获
1.链表一定要分清节点和指针的概念。 new ListNode()是真实存在的一个节点, head = new ListNode() 相当于 head指针指向了一个真实的节点, node = head, 相当于node和head同时指向了这个真实的节点
2.先写出双指针,再写递归的方法