你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性: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 的节点。
示例:
输入
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]
解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3
myLinkedList.get(1); // 返回 2
myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3
myLinkedList.get(1); // 返回 3
链表操作的两种方式:
直接使用原来的链表来进行操作。
设置一个虚拟头结点在进行操作。
方法一:设置虚拟头节点
class ListNode{
constructor(val,next){
this.val = val
this.next = next
}
}
var MyLinkedList = function() {
this.length = 0
this.head = null
this.tail = null
};
/**
* @param {number} index
* @return {number}
*/
MyLinkedList.prototype.getNode = function(index) {
if(index < 0 || index >= this.length) return null;
// 创建虚拟头节点
let cur = new ListNode(0, this.head);
// 0 -> head
while(index-- >= 0) {
cur = cur.next;
}
return cur;
};
MyLinkedList.prototype.get = function(index) {
if(index<0||index>=this.length) return -1
return this.getNode(index).val
};
/**
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtHead = function(val) {
var node = new ListNode(val,this.head) //创建一个:值为val,指向this.head的节点
this.head = node //将该节点变为头节点
this.length++
if(!this.tail){ //为空链表时,头和尾为同一个空节点
this.tail = node
}
};
/**
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtTail = function(val) {
var node = new ListNode(val,null) //创建一个:值为val,指向null的节点
this.length++
while(this.tail){ //尾节点存在时
this.tail.next = node //将链表的尾节点指向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.length) return;
if(index<=0){
this.addAtHead(val)
return;
}
if(index==this.length){
this.addAtTail(val)
return;
}
var node = this.getNode(index-1) //设index前一个节点为node节点
node.next = new ListNode(val,node.next)
this.length++
};
/**
* @param {number} index
* @return {void}
*/
MyLinkedList.prototype.deleteAtIndex = function(index) {
if(index<0||index>=this.length) return;
if(index==0){ //要删除的是头节点
this.head = this.head.next
if(index==this.length-1){ //链表中只有一个节点,即头尾节点为同一个
this.tail = this.head
}
this.length --
return;
}
var node = this.getNode(index-1)
node.next = node.next.next
if(index == this.length-1){ //要删除的是尾节点
this.tail = node
}
this.length--
};
方法二
var MyLinkedList = function () {
this.val = []
};
MyLinkedList.prototype.get = function (index) {
return this.val[index] === undefined ? -1 : this.val[index]
};
MyLinkedList.prototype.addAtHead = function (val) {
this.val.unshift(val)
};
MyLinkedList.prototype.addAtTail = function (val) {
this.val.push(val)
};
MyLinkedList.prototype.addAtIndex = function (index, val) {
if (index <= 0) {
this.val.unshift(val)
} else if (index === this.val.length) {
this.val.push(val)
} else if (index > 0 && index < this.val.length) {
this.val.splice(index, 0, val) //在 index 节点删除 0 个值,并加入 val
}
};
MyLinkedList.prototype.deleteAtIndex = function (index) {
if (this.val[index] !== undefined) {
this.val.splice(index, 1)
}
};