题一 移除链表元素
题目链接: 移除链表元素
解题思路: 有俩种解题思路,第一种是不使用虚拟头节点,这个时候我们需要对头节点做特殊的处理,即head.val = val, head = head.next; 然后才能对非头节点进行处理,如果我们增加了一个虚拟头节点dummy_head指向头节点,这下对原链表的处理操作全都可以变成对非头节点的处理操作了,方便了我们的操作。
解题代码:
- 不使用虚拟头节点
var removeElements = function(head, val) {
// 如果头节点的值是目标值或者是头节点后连续的节点为目标值的情况下
while(head!= null && head.val === val){
head = head.next;
}
// 此时头节点不为目标节点了 接下来就是处理非头节点的情况
let cur = head;
while(cur !== null && cur.next !== null){ // 这里把cur不等于null的情况加进来是因为 在head为null的情况下接下来的操作就没有意义了 还有一种情况就是当cur.next为空的情况下就不需要遍历了 因为我们每一步都是判断cur.next的值
if(cur.next.val === val){
cur.next = cur.next.next; // 删除
}else{
cur = cur.next; // 向右移位
}
}
return head; // 因为我们没有动过head 所以返回的head仍然是原头节点
};
- 使用虚拟头节点
var removeElements = function(head,val){
let dummy_head = new ListNode();
dummy_head.next = head;
let cur = dummy_head;
while(cur.next){
if(cur.next.val === val){
cur.next = cur.next.next;
}else{
cur = cur.next;
}
}
return dummy_head.next;
}
题目二 设计链表
题目链接:设计链表
解题思路: 这道题考查的还是对链表的基本操作,没有什么难点,我觉得最重要的是对链表的设计
var MyLinkedList = function () {
this._size = 0;
this._tail = null;
this._head = null;
};
class LinkNode {
constructor(val, next) {
this.val = val;
this.next = next;
}
}
然后最好采用虚拟头节点的方式操作链表,这样不会对链表真正的头节点造成影响。
解题代码:
MyLinkedList.prototype.getNode = function (index) {
if (index < 0 || index >= this._size) return null;
// 创建虚拟头节点
let cur = new LinkNode(0, this._head);
// 0 -> head
while (index-- >= 0) {
cur = cur.next;
}
return cur;
};
/**
* @param {number} index
* @return {number}
*/
MyLinkedList.prototype.get = function (index) {
// 最重要的是得找到位置为index的节点
if (index < 0 || index > this._size - 1) {
return -1;
}
let cur = new ListNode(null, this._head)
while (index-- >= 0) {
cur = cur.next;
}
return cur.val;
};
/**
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtHead = function (val) {
// 在头部插入节点 更新链表头节点的值
let newNode = new ListNode(val, this._head);
this._head = newNode;
if (this._size === 0) {
this._tail = newNode;
}
this._size++;
console.log('在头部插入后:', this)
};
/**
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtTail = function (val) {
let newNode = new ListNode(val, null);
let dummy_head = new ListNode(null, this._head);
let cur = dummy_head;
while (cur.next) {
cur = cur.next;
}
cur.next = newNode;
this._tail = newNode;
if (this._size === 0) {
this._head = newNode;
}
this._size++;
console.log('在尾部插入后:', this);
};
/**
* @param {number} index
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtIndex = function (index, val) {
if (index > this._size) {
return null;
} else if (index <= 0) {
return this.addAtHead(val);
} else if (index === this._size) {
return this.addAtTail(val);
} else {
let cur = new ListNode(null, this._head);
let newCode = new ListNode(val, null);
while (index--) {
cur = cur.next;
}
newCode.next = cur.next;
cur.next = newCode;
this._size++;
console.log('正常插入后:', this)
}
};
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;
}
// 获取目标节点的上一个的节点
const node = this.getNode(index - 1);
node.next = node.next.next;
// 处理尾节点
if (index === this._size - 1) {
this._tail = node;
}
this._size--;
};
题三 反转链表
题目链接: https://leetcode.cn/problems/reverse-linked-list/
解题思路: 要反转链表,就要搞清每一个单元的反转方式,设置一个pre节点指向null,一个cur节点指向head,这里的反转逻辑是,temp=cur.next, pre.next = cur.next cur.next = pre, cur = tmp, 直到cur.next为空的时候链表反转结束,此时cur节点就是反转链表后的新的头节点。
解题代码:
/* var reverseList = function (head) {
let cur = new ListNode(null, null);
let pre = null;
cur = head;
while (cur) {
let tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}; */
/**
* 法二:递归
*/
var reverse = function(cur,pre){
if(!cur)return pre;
let temp = cur.next;
cur.next = pre;
return reverse(temp,cur);
}
var reverseList = function(head) {
return reverse(head,null);
};