Javascript算法实现:反转链表 旋转链表 链表相交 数据流中的第K大元素 翻转二叉树
2023-11-02 19:12:00
揭秘链表和二叉树的五大经典算法
在计算机科学中,数据结构和算法是至关重要的基石。其中,链表和二叉树是两种广泛使用的非线性数据结构,广泛应用于各种应用中。本文将深入探讨与链表和二叉树相关的五大经典算法,它们是程序员必备的技能。
1. 反转链表
链表是一种线性数据结构,由一组节点组成,每个节点包含一个值和指向下一个节点的指针。反转链表是将其节点的顺序从头到尾颠倒的过程。反转链表的一个简单方法是使用三个指针:前一个指针指向当前节点的前一个节点,当前指针指向当前节点,下一个指针指向当前节点的下一个节点。然后,将当前节点的下一个指针指向前一个节点,并将前一个节点指向当前节点,最后将当前节点移动到下一个节点。重复这个过程,直到遍历完整个链表。
function reverseList(head) {
let prev = null;
let curr = head;
while (curr) {
const next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
2. 旋转链表
旋转链表是将链表向右旋转一定位置的过程。给定一个链表和一个旋转位置,我们可以将链表分为两部分:第一部分是需要旋转的部分,第二部分是剩下的部分。然后,将第二部分连接到第一部分的尾部,并断开第一部分的尾部与第二部分的连接。最后,将第二部分的头节点作为旋转后的链表的头节点返回。
function rotateRight(head, k) {
if (!head || !head.next || k === 0) {
return head;
}
let len = 1;
let curr = head;
while (curr.next) {
curr = curr.next;
len++;
}
k %= len;
if (k === 0) {
return head;
}
let slow = head;
let fast = head;
while (k--) {
fast = fast.next;
}
while (fast.next) {
slow = slow.next;
fast = fast.next;
}
const newHead = slow.next;
slow.next = null;
fast.next = head;
return newHead;
}
3. 链表相交
链表相交问题是指判断两个链表是否相交,以及相交的话返回相交的节点。我们可以使用两个指针,一个指针指向第一个链表的头节点,另一个指针指向第二个链表的头节点。然后,两个指针同时遍历两个链表,当其中一个指针到达链表的尾部时,就重新指向另一个链表的头节点。重复这个过程,直到两个指针相遇或者两个指针都到达链表的尾部。如果两个指针相遇,则表明两个链表相交,返回相交结点的值。如果两个指针都到达链表的尾部,则表明两个链表不相交,返回-1。
function getIntersectionNode(headA, headB) {
let pA = headA;
let pB = headB;
while (pA !== pB) {
pA = pA ? pA.next : headB;
pB = pB ? pB.next : headA;
}
return pA;
}
4. 数据流中的第K大元素
数据流中的第K大元素问题是指,给定一个数据流,要求随时返回数据流中第K大的元素。我们可以使用一个小顶堆来保存数据流中的元素。小顶堆是一种数据结构,它可以快速地找到堆中的最小元素。当数据流中的元素超过K个时,将堆中的最小元素弹出,然后将新元素插入堆中。这样,堆中始终保存着数据流中最大的K个元素,并且堆顶的元素就是数据流中的第K大元素。
class KthLargest {
constructor(k) {
this.k = k;
this.heap = [];
}
add(val) {
this.heap.push(val);
this.heap.sort((a, b) => a - b);
if (this.heap.length > this.k) {
this.heap.shift();
}
}
getKthLargest() {
return this.heap[0];
}
}
5. 翻转二叉树
翻转二叉树是指将二叉树的左右子树交换。我们可以使用递归来遍历二叉树。在遍历每个节点时,将它的左右子树交换,然后递归地遍历它的左右子树。这样,整棵二叉树就会被翻转。
function invertTree(root) {
if (!root) {
return null;
}
const left = invertTree(root.left);
const right = invertTree(root.right);
root.left = right;
root.right = left;
return root;
}
常见问题解答
1. 链表和二叉树有什么区别?
链表是一种线性数据结构,由一组节点组成,每个节点包含一个值和指向下一个节点的指针。二叉树是一种树形数据结构,由一个根节点组成,每个节点最多有两个子节点。
2. 反转链表和旋转链表有什么区别?
反转链表是将链表的顺序从头到尾颠倒,而旋转链表是将链表向右旋转一定位置。
3. 链表相交问题如何处理环形链表?
对于环形链表,可以使用快慢指针法来检测相交。快指针每次移动两步,慢指针每次移动一步。如果快指针和慢指针相遇,则表明链表存在环。
4. 数据流中的第K大元素问题如何处理无序数据?
对于无序数据,可以使用快速选择算法来找到第K大元素。快速选择算法是一种基于分治的排序算法,它可以快速地找到数组中第K大元素。
5. 翻转二叉树会影响二叉树的遍历顺序吗?
翻转二叉树不会影响二叉树的遍历顺序。例如,对于前序遍历,翻转二叉树后,遍历顺序仍然是根节点、左子树、右子树。