定义结点
class ListNode { // 结点类
val; // 存结点的数据 属性
next = null; // 指向下一个结点的指针
constructor(value){ // 构造函数
this.val = value;
this.next = null;
}
}
203移除链表元素
203.移除链表元素
重点为头结点移除,技巧为使用虚拟头结点
- 不用虚拟头结点,直接单独处理删除头结点-->**头指针head后移 **
- 头结点head前面加一个虚拟头结点,直接用和删除之后元素一样的方法,删除头结点,最后返回虚拟头结点下一个
- C++要自己释放内存,JS有内存回收不用自己释放
本质:只能删除指针指的下一个(必须知道前面一个)
技巧:直接判断这种情况,处理临界值
首先肯定要设虚拟头结点,明确
cur指向正在判断的结点,pre指向它的前一个,有两种情况:
- 正在判断的
cur,是要删的:越过要删的,cur指向要删的下一个,继续判断 - 正在判断的
cur,不是要删的:pre/cur都往后移
虚拟头结点(重要)
方便操作
/**
* 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 dhead = new ListNode(0, head) //虚拟头结点,指向头结点
let pre = dhead //前指针
let cur = pre.next //指向正在判断的
while (pre && cur) { //直接根据图中临界情况,都不为空
if (cur.val === val) { //正在判断的是要删的值
pre.next = cur.next //越过要删的
cur = pre.next //正在判断的值,更新为下一个
} else { //正在判断的不是要删的
pre = cur //直接都往前移
cur = cur.next
}
}
return dhead.next //返回真正的头结点
};
707.设计链表
设计链表 原则:可以对指针的下一个进行操作 技巧:用index=0这个特殊的点去验证,一定自己画图
JS题解
首先先理解题目的意思!
因为最开始初始化时
size = 0,头结点对应的应该是虚拟头
- 不是链表所有操作都需要虚拟头结点,增删元素时用虚头,不用考虑头结点
class ListNode { //链表结点类
constructor (val, next) { //构造函数
this.val = (val === undefined ? 0 :val)
this.next = (next === undefined ? null : next)
}
}
var MyLinkedList = function() { //链表的构造函数
// 链表的属性
this.size = 0, //大小
this.dhead = new ListNode(0) //虚拟头结点,对应size为0
// 下面在原型中加入链表的方法
};
/**
* 获取index结点值的函数
* @param {number} index
* @return {number}
*/
//找第index个元素(0 ~ n-1),索引无效,则返回-1
MyLinkedList.prototype.get = function(index) {
if(index > this.size - 1 || index < 0) { //越界:索引无效直接return-1
return -1
}
let cur = this.dhead //从头
while (index >= 0) {
cur = cur.next //向后找
index--
}
return cur.val //找到返回值
};
/**
* @param {number} val
* @return {void}
*/
//第一个前面加值val结点,变为头结点
MyLinkedList.prototype.addAtHead = function(val) {
//直接加到头结点下一个
let newNode = new ListNode(val, null) //定义新节点
newNode.next = this.dhead.next //一定要按顺序来
this.dhead.next = newNode
this.size++ //加入之后大小+1
};
/**
* @param {number} val
* @return {void}
*/
// 在链表最后加值val结点
MyLinkedList.prototype.addAtTail = function(val) {
// 找最后一个
let cur = this.dhead;
while (cur.next !== null) {
cur = cur.next
}
// 插入链表
let newNode = new ListNode(val, null)
cur.next = newNode
this.size++ //记得大小+1
};
/**
* @param {number} index
* @param {number} val
* @return {void}
*/
// 第 index 个节点之前添加值为 val 的节点
// 如果index = 链表的长度,插到尾结点
// 如果index 大于 链表的长度,则返回空
// 如果index 小于0,则在头部插入节点--相当于index = 0
MyLinkedList.prototype.addAtIndex = function(index, val) {
if (index > this.size) return // 不插直接return
else if (index < 0) this.addAtHead(val) // 插在头,相当于index = 0
else if (index == this.size) this.addAtTail(val) //插到尾
else{
let cur = this.dhead // index=0时在dhead后面插
while (index--) {
cur = cur.next
}
let newNode = new ListNode(val, null) // 要插入的新节点
newNode.next = cur.next // 插入
cur.next = newNode
this.size++
}
};
/**
* @param {number} index
* @return {void}
*/
//删除第index个结点
MyLinkedList.prototype.deleteAtIndex = function(index) {
if (index > this.size - 1 || index < 0) return; //越界直接return
let cur = this.dhead
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.反转链表
(重点)双指针法
注意:cur初始为head,pre为它前面一个,初始化为null因为第一次反转操作就可以直接让尾指向空
首先
tmp存cur的下一个,再进行反转,反转完之后,指针前移
终止条件是cur指向null不用再反转了,最后头结点为pre
/**
* 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 cur = head
let pre = null
let tmp = null
while (cur) {
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
}
return pre
};