203-移除链表元素
【分析】
1、题干背景:需要移除链表节点的val值等于传入的val值的节点
2、这道题允许返回一个新的头节点,可以认为可返回新的链表
【疑问】
1、链表如何遍历?
通常链表遍历通常当前节点初始值设置为头节点,然后通过next指针来移动当前节点的位置
2、如何创建新的节点?
通常是通过构造函数LinkedList。这个构造函数可以自己手写
具体逻辑如下
function LinkedList(val,next){
this.val = val === undefined ? 0 : val;
this.next = this.next === null ? null : next;
}
3、创建新链表是否需要区分头节点的创建?
这个是需要区分的,因为头节点需要有个标志,才能后续用来返回链表的头节点
【代码实现】
var removeElements = function(head, val) {
let nodeList = null;
let headNode = null;
let curNode = head;
while(curNode){
if(curNode.val !== val){
// 说明需要收集
if(nodeList===null){
// 说明是头节点
nodeList = new ListNode(curNode.val);
headNode = nodeList;
}else{
nodeList.next = new ListNode(curNode.val);
nodeList = nodeList.next;
}
}
curNode=curNode.next;
}
return headNode
}
707-设计链表
【分析】
1、题干背景:这道题就是用来考察链表的结构基础的
2、关键就是要读懂每个方法的作用,以及入参和返回值即可
3、值得注意的是头尾节点的问题,新增需要考虑,删除也同样需要考虑
4、在每次变动时,链表的长度都会发生相应的变化,这也是容易遗漏的地方
【疑问】
1、单链表需要哪些属性?
1、头节点
2、尾节点
3、链表长度
2、头部新增如何处理?
只需要创建一个新的节点,并且借助构造函数内部的head属性,将新节点的next指向原本的head节点,再将head变量指向新节点
这里需要考虑this.head为null的情况,为null说明这是第一次添加节点,那么在修改head的同时,也要考虑tail的情况
const newNode = new ListNode(1);
newNode.next = this.head;
if(this.head === null) this.tail = newNode;
this.head = newNode;
3、尾部新增如何处理?
同样创建一个新节点,借助构造函数内部的tail属性,将原本的tail的next指向新节点,并且将tail变量指向新节点即可
这里需要额外注意一点,如果this.tail为null的情况,说明当前链表还没有任何节点,所以在赋值的时候需要考虑head
const newNode = new ListNode(1);
if(this.tail){
this.tail.next = newNode;
this.tail = newNode;
}else{
this.head = newNode;
this.tail = newNode;
}
【代码实现】
这一版代码写的比较乱,后续再重新梳理一下逻辑
var MyLinkedList = function (val, next) {
this.length = val ? 1 : 0;
// 初始化,可能传值可能不传值
this.head = val ? new ListNode(val) : null;
if (this.head) {
this.head.next = next; // 这里需要建立关联
}
if (next) {
let curNode = next;
while (curNode) {
this.tail = curNode;
curNode = curNode.next;
this.length++;
}
} else {
this.tail = this.head;
}
};
/**
* @param {number} index
* @return {number}
*/
MyLinkedList.prototype.get = function (index) {
const node = this.getNode(index);
return node === null ? -1 : node.val;
};
MyLinkedList.prototype.getNode = function (index) {
// 说明这个索引的值是不存在的
if (index >= this.length) return null;
let curNode = this.head;
let count = 0;
while (curNode) {
if (count === index) {
return curNode;
}
curNode = curNode.next;
count++;
}
return null;
};
/**
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtHead = function (val) {
const node = new ListNode(val);
// 需要考虑头节点在不在
if (this.head) {
node.next = this.head;
this.head = node;
} else {
this.head = node;
this.tail = node;
}
this.length++;
};
/**
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtTail = function (val) {
const node = new ListNode(val);
if (this.tail) {
this.tail.next = node;
this.tail = node;
} else {
this.head = node;
this.tail = node;
}
this.length++;
};
/**
* @param {number} index
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtIndex = function (index, val) {
if (index > this.length) return;
else if (index === this.length) {
this.addAtTail(val);
} else if (index === 0) {
this.addAtHead(val);
} else {
const node = this.getNode(index - 1);
const nextNode = node.next;
const newNode = new ListNode(val);
newNode.next = nextNode;
node.next = newNode;
this.length++;
}
};
/**
* @param {number} index
* @return {void}
*/
MyLinkedList.prototype.deleteAtIndex = function (index) {
if (index >= this.length) return;
if (index === 0) {
// 考虑了头部
this.head = this.head.next;
this.tail = this.head ? this.tail : null;
} else {
const node = this.getNode(index - 1);
node.next = node.next ? node.next.next : null;
if (node.next === null) {
this.tail = node;
}
}
this.length--;
};
206-反转链表
【分析】
1、题干背景:这道题需要将链表的顺序翻转一下
2、总体思路仍然还是围绕着修改next指针,可能容易绕晕的地方在于原next指向和新next指向的替换
3、遍历链表的顺序是从前往后,翻转后是从后往前,所以其实可以认为每次遍历的节点都需要插入到新链表的头部
【疑问】
1、如何实现节点next指针的值改变?
我们需要借助两个变量,一个是当前节点,一个上一个节点
按照顺序来说,结构为上一个节点 -> 当前节点
按照反序来说,结构为当前节点 -> 上一个节点
所以整体思路是:
原有的当前节点的next节点,作为下一次循环的当前节点
当前节点的next节点需要更新为之前存储的上一个节点
const nextNode = curNode.next;//这是下一次循环的当前节点
curNode.next = lastNode;
lastNode = curNode;
curNode = nextNode;// 这个赋值操作主要是因为while循环判断是通过curNode,所以表示下一次循环的判断条件是nextNode
【代码实现】
var reverseList = function(head) {
let curNode = head;
let lastNode = null;
while(curNode){
const node = curNode;
curNode = curNode.next;
node.next = lastNode;
lastNode = node;
}
return lastNode;//因为翻转其实是一直在改变新链表的头节点,所以返回lastNode
};