返回
匠心独运:有序链表巧变平衡二叉树,算法妙招令人叹服
前端
2024-01-04 20:16:39
引言
算法的世界犹如浩瀚星空,处处闪烁着智慧的星光。今天,我们聚焦于一道经典的题目:将有序链表转换为平衡二叉搜索树。这道看似复杂的题目,背后却蕴藏着算法设计的精妙与优雅。
转换数组法:直观易懂
转换数组法是一种将有序链表转换为二叉搜索树最直接的方法。其核心思路是:
- 将链表中的所有元素依次取出,放入一个数组中。
- 对数组进行中序遍历,以递归的方式构建二叉搜索树。
function sortedListToBST(head) {
const arr = [];
while (head) {
arr.push(head.val);
head = head.next;
}
return buildBST(arr, 0, arr.length - 1);
}
function buildBST(arr, start, end) {
if (start > end) return null;
const mid = Math.floor((start + end) / 2);
const node = new TreeNode(arr[mid]);
node.left = buildBST(arr, start, mid - 1);
node.right = buildBST(arr, mid + 1, end);
return node;
}
递归回溯法:简洁高效
递归回溯法是一种更简洁高效的解法。其思路是:
- 寻找链表的中间节点,作为二叉搜索树的根节点。
- 递归地将中间节点的左半部分转换为左子树,右半部分转换为右子树。
function sortedListToBST(head) {
if (!head) return null;
const mid = findMiddle(head);
const root = new TreeNode(mid.val);
root.left = sortedListToBST(head);
root.right = sortedListToBST(mid.next);
return root;
}
function findMiddle(head) {
let slow = head;
let fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
递归回溯与中序遍历:巧妙结合
递归回溯与中序遍历相结合的解法,是一种更具技巧性的方法。其思路是:
- 中序遍历链表,将元素依次压入栈中。
- 递归地将栈顶元素弹出,作为二叉搜索树的根节点。
- 递归地将根节点的左半部分和右半部分分别转换为左子树和右子树。
function sortedListToBST(head) {
const stack = [];
inorder(head, stack);
return buildBST(stack);
}
function inorder(head, stack) {
if (!head) return;
inorder(head.left, stack);
stack.push(head.val);
inorder(head.right, stack);
}
function buildBST(stack) {
if (stack.length === 0) return null;
const root = new TreeNode(stack.pop());
root.left = buildBST(stack);
root.right = buildBST(stack);
return root;
}
总结
将有序链表转换为平衡二叉搜索树的算法,为我们展示了算法设计的多样性和巧妙性。从直观的转换数组法到简洁高效的递归回溯法,再到将递归回溯与中序遍历巧妙结合的解法,每一种方法都体现了算法设计师的智慧与创造力。
无论你选择哪种方法,深入理解背后的思想和原理才是最重要的。只有真正掌握算法的精髓,才能在解决实际问题时游刃有余,将算法的魅力发挥到极致。