-
207. 移除链表元素
【思路】考虑两种方法。- 直接从头节点开始遍历,但当目标值是头节点时,要单独处理。因为移除其他节点是通过前一个节点的指针来移除的,头节点没有前一个节点,只能让 head 向后移删除头节点。
- 在头节点前边加一个虚拟节点,就不用特殊处理头节点。
var removeElements = function(head, val) { // 添加一个虚拟节点 const ret = new ListNode(0, head); let cur = ret; while (cur.next) { if (cur.next.val === val) { cur.next = cur.next.next; continue; } cur = cur.next; } return ret.next; };
-
707. 设计列表
【总结】需要注意的地方:- 时刻注意 index 和 value 的值是否有效
- 在插入和删除节点的时候特别注意原本列表为空或操作之后是否剩下一个节点的情况,操作后剩下一个节点时首尾指针都要指向该节点
- 插入操作时要注意赋值顺序,
node.next = cur.next
之后再cur.next = node
,否则会有坑! - 记得每一个操作考虑好数组的长度与 index 之间的大小,多分情况讨论就好噜!
- 获取第 index 个节点用的频繁,就单独封装了个函数。芜湖~!
class LinkNode { constructor(val, next) { this.val = val; this.next = next; } } // 单链表储存头尾节点和节点数量 var MyLinkedList = function() { this._size = 0; this._tail = null; this._head = null; }; /** * @param {number} index * @return {void} */ // 获取第 index 个节点 MyLinkedList.prototype.getNode = function(index) { if (index < 0 || index >= this._size) return; let cur = new LinkNode(0, this._head); while (index-- >= 0) { cur = cur.next; } return cur; } /** * @param {number} index * @return {number} */ // 获取列表中第 index 个节点的值。如果索引无效返回 -1 MyLinkedList.prototype.get = function(index) { // 排除 index 值无效 if (index < 0 || index >= this._size) return -1; let node = this.getNode(index); return node.val; }; /** * @param {number} val * @return {void} */ // 在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点 MyLinkedList.prototype.addAtHead = function(val) { let node = new LinkNode(val, this._head); this._head = node; this._size++; // 考虑原本链表为空的情况,此时首尾节点都是 node 节点 if (!this._tail) { this._tail = node; } }; /** * @param {number} val * @return {void} */ // 将值为 val 的节点追加到链表的最后一个元素 MyLinkedList.prototype.addAtTail = function(val) { // 创建一个新节点 let node = new LinkNode(val, null); this._size++; if (this._tail) { this._tail.next = node; this._tail = node; return; } // 假如链接为空,则首尾节点都是 node this._tail = node; this._head = node; }; /** * @param {number} index * @param {number} val * @return {void} */ // 在链表中的第 index 个节点之前插入值为 val 的节点,如果 index 等于链表的长度,则该节点将附加到链表的末尾。 // 如果 index > this._size,则不会插入节点,如果 index < 0, 则在头部插入节点 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; } let node = this.getNode(index - 1); let cur = new LinkNode(val, node.next); node.next = cur; this._size++; }; /** * @param {number} index * @return {void} */ // 如果索引 index 有效,则删除链表中的 第 index 节点 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; } let node = this.getNode(index - 1); node.next = node.next.next // 删除尾节点时 if (index === this._size - 1) { this._tail = node; } this._size--; };
-
206. 反转链表
【思路】可以用双指针法或者递归来做。(递归还有点迷糊的!先把双指针写好,照着慢点写!)
// 双指针法
var reverseList = function(head) {
// 链表为空或者链表只有一个节点
if (!head || !head.next) return head;
let cur = head, pre = null;
while (cur) { // 当 cur = null 时,代表反转结束
let temp = cur.next;
cur.next = pre; // 反转数组
pre = cur;
cur = temp;
}
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); // reverse(pre, cur);
}
参考代码随想录:https://www.programmercarl.com/