代码随想录算法训练营第四天 | LeetCode 24. 两两交换链表中的节点, 19. 删除链表的倒数第N个节点, 160. 链表相交, 142. 环形链表II
LeetCode 24. 两两交换链表中的节点
let swapPairs = function (head) {
let dummy = new ListNode(0, head), cur = dummy;
// 保证了只有连续两个节点都存在时才进行交换
while (cur.next && cur.next.next){
// 定义临时变量保存下一个交换对的起始节点(不然赋值完就丢了)
let temp = cur.next.next.next
cur.next.next.next = cur.next
cur.next = cur.next.next
cur.next.next.next = temp
cur = cur.next.next // // 移动指针到下一个交换对的起始节点
}
}
要注意赋值的顺序,和哪个值/节点需要被临时储存
LeetCode 19. 删除链表的倒数第N个节点
let removeNthFromEnd = function (head, n) {
let dummy = new ListNode(0, head)
let slow = dummy
let fast = dummy
for (let i = 0; i < n+1; i++){
fast = fast.next // fast在slow右侧n+1距离的位置
}
// 如果fast已经指向null了,要删除的节点就是第一个节点,运用虚拟头节点删
if (fast === null) {
dummy.next = dummy.next.next
return dummy.next
}
while (fast !== null) {
fast = fast.next
slow = slow.next
}
slow.next = slow.next.next // 删除slow所指向的节点
return dummy.next // 返回整个链表
}
LeetCode 160. 链表相交
let getIntersectionNode = function (headA, headB) {
let visited = new Set()
let cur = headA
while (cur){
visited.add(cur)
cur = cur.next
}
cur = headB
while(cur){
if (visited.has(cur)){
return cur
} else{
cur = cur.next
}
}
return null
}
首先,代码定义了一个 Set 集合 visited,用于存储遍历过的节点。
然后,从链表 headA 开始,遍历链表中的每个节点,将其添加到 visited 集合中。
接下来,从链表 headB 开始遍历,对于每个节点,检查它是否在 visited 集合中出现过。如果出现过,说明当前节点是两个链表的交点,直接返回该节点即可。
如果整个链表都遍历完了还没有找到交点,则返回 null。
LeetCode 142. 环形链表II
let detectCycle = function (head) {
let visited = new Set()
let cur = head
while (cur) {
if (visited.has(cur)) {
return cur
} else {
visited.add(cur)
cur = cur.next
}
}
return null
}
和上一题很类似
反思:为什么不用List
list的底层实现是顺序表,查找的算法是顺序遍历查找,因此复杂度为O(n)
set的底层实现是哈希表(散列表),查找算法是利用红黑树进行查找,因此时间复杂度为O(logn)
没有索引的需求就用set