链表相关的操作
链表是否有环
// 判断是否有环,有返回入口节点,无返回null·
let hasCycle = function(head) {
let set = new Set();
while (head != null) {
if (set.has(head)) {
return head;
} else {
set.add(head)
head = head.next;
}
}
return null;
};
利用 json.stringify 不能序列化含有循环引用的结构
let hasCycle = function(head) {
try{
JSON.stringify(head);
return false;
}
catch(err){
return true;
}
};
解法三:快慢指针(双指针法) 设置快慢两个指针,遍历单链表,快指针一次走两步,慢指针一次走一步,如果单链表中存在环,则快慢指针终会指向同一个节点,否则直到快指针指向 null 时,快慢指针都不可能相遇
let hasCycle = function(head) {
if(!head || !head.next) {
return false
}
let fast = head.next.next, slow = head.next
while(fast !== slow) {
if(!fast || !fast.next) return false
fast = fast.next.next
slow = slow.next
}
return true
};
链表反转(反转链表)
function reverse(head){
if(!head || !head.next) return head;
var prev = null, cur = head;
while(cur){
// 用于临时存储 cur 后继节点
var next = curr.next;
// 反转 cur 的后继指针
cur.next = prev;
// 变更 prev, cur
prev = cur
cur = next
}
return prev
}
链表倒数第 k 个节点
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var getKthFromEnd = function(head, k) {
let fast = head
let slow = head
let i = 0
while(i++ < k) {
fast = fast.next
}
while(fast) {
fast = fast.next
slow = slow.next
}
return slow
};
合并两个有序链表
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
function mergeTwoLists(l1, l2) {
if(l1 === null) {
return l2
}
if(l2 === null) {
return l1
}
if(l1.val <= l2.val) {
l1.next = mergeTwoLists(l1.next, l2)
return l1
} else {
l2.next = mergeTwoLists(l2.next, l1)
return l2
}
}
两两交换链表中的节点
递归的终止条件是链表中没有节点,或者链表中只有一个节点,此时无法进行交换。
/**
* 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 swapPairs = function(head) {
if (head === null || head.next === null) {
return head;
}
const newHead = head.next;
head.next = swapPairs(newHead.next);
newHead.next = head;
return newHead;
};
这边其实分为三个步骤
首先判断 head 有没有 和 head。next 有没有存在
原始链表的头节点是 newHead 表示新的链表的头节点, 原始链表的第二个节点, 则原始链表的其余节点的头节点是 newHead.next。 令head.next = swapPairs(newHead.next), 表示将其余节点进行两两交换, 交换后的新的节点为head的下一个节点,
然后令 newHead.next = head,即可完成所有节点的交换。 最后返回新的链表的头节点 newHead。
反转从位置 m 到 n 的链表
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} m
* @param {number} n
* @return {ListNode}
*/
var reverseBetween = function(head, m, n) {
// 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
var dummy = new ListNode(-1)
dummy.next = head
var prev = dummy
//第一步:从虚拟头节点走 m-1 步,来到第 m 个节点的前一个节点
var cur = head
var reverse = null
var reverseLastNode = null
var index = 1
while(index <= n) {
if(index < m) {
prev = prev.next;
cur = cur.next;
} else {
// 反转前的第一个节点,也就是反转后的最后一个节点
if(reverseLastNode === null) {
reverseLastNode = cur;
}
// 交换
var temp = reverse;
reverse = cur;
cur = cur.next;
reverse.next = temp;
}
index++;
}
prev.next = reverse;
reverseLastNode.next = cur;
return dummy.next
};
/*输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
*/
删除中间节点
但是本题中我们只能访问要删除的节点,所以这个方法用不了。那我们可以把当前节点的下一个节点的值拿过来覆盖掉要删除的值,然后把当前节点的 next 指向下一个节点的 next 即可。
var deleteNode = function(node){
node.val = node.next.val;
node.next = node.next.next;
}
最后更新于
这有帮助吗?