|
| 1 | +// 109. Convert Sorted List to Binary Search Tree |
| 2 | +// 🟠 Medium |
| 3 | +// |
| 4 | +// https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/ |
| 5 | +// |
| 6 | +// Tags: Linked List - Divide and Conquer - Tree - Binary Search Tree - Binary Tree |
| 7 | + |
| 8 | +// Definition for singly-linked list. |
| 9 | +use std::cell::RefCell; |
| 10 | +use std::rc::Rc; |
| 11 | +#[derive(PartialEq, Eq, Clone, Debug)] |
| 12 | +pub struct ListNode { |
| 13 | + pub val: i32, |
| 14 | + pub next: Option<Box<ListNode>>, |
| 15 | +} |
| 16 | + |
| 17 | +impl ListNode { |
| 18 | + #[inline] |
| 19 | + fn new(val: i32) -> Self { |
| 20 | + ListNode { next: None, val } |
| 21 | + } |
| 22 | +} |
| 23 | +// Definition for a binary tree node. |
| 24 | +#[derive(Debug, PartialEq, Eq)] |
| 25 | +pub struct TreeNode { |
| 26 | + pub val: i32, |
| 27 | + pub left: Option<Rc<RefCell<TreeNode>>>, |
| 28 | + pub right: Option<Rc<RefCell<TreeNode>>>, |
| 29 | +} |
| 30 | + |
| 31 | +impl TreeNode { |
| 32 | + #[inline] |
| 33 | + pub fn new(val: i32) -> Self { |
| 34 | + TreeNode { |
| 35 | + val, |
| 36 | + left: None, |
| 37 | + right: None, |
| 38 | + } |
| 39 | + } |
| 40 | +} |
| 41 | +struct Solution; |
| 42 | +impl Solution { |
| 43 | + // Use a divide and conquer approach, use two pointers to find the middle |
| 44 | + // of the linked list, use the middle node as the root of the BST, then |
| 45 | + // use two recursive calls with the unused left and right linked lists to |
| 46 | + // generate the left and right subtrees. Solution inspired by: |
| 47 | + // https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/solutions/3282679 |
| 48 | + // Even though I find the two pointer solution more elegant, in Rust it |
| 49 | + // seems like converting to array and using the same logic as in 108 |
| 50 | + // performs better. |
| 51 | + // |
| 52 | + // Time complexity: O(n) - Each node will be visited one, two or three |
| 53 | + // times. |
| 54 | + // Space complexity: O(log(n)) - The height of the call stack. |
| 55 | + // |
| 56 | + // Runtime 466 ms Beats 14.29% |
| 57 | + // Memory 4 MB Beats 42.86% |
| 58 | + pub fn sorted_list_to_bst(head: Option<Box<ListNode>>) -> Option<Rc<RefCell<TreeNode>>> { |
| 59 | + match head { |
| 60 | + Some(_) => Self::slice_to_bst(head.as_ref(), None), |
| 61 | + None => None, |
| 62 | + } |
| 63 | + } |
| 64 | + |
| 65 | + // An auxiliary function that converts a segment of a linked list to a BST |
| 66 | + // and returns the root. |
| 67 | + fn slice_to_bst( |
| 68 | + first: Option<&Box<ListNode>>, |
| 69 | + last: Option<&Box<ListNode>>, |
| 70 | + ) -> Option<Rc<RefCell<TreeNode>>> { |
| 71 | + // If the segment is empty, return an empty tree. |
| 72 | + if first == last { |
| 73 | + return None; |
| 74 | + } |
| 75 | + // Use a fast and slow pointers. |
| 76 | + let (mut slow, mut fast) = (first, first); |
| 77 | + let mut fast_next: Option<&Box<ListNode>>; |
| 78 | + // Iterate over the list while fast is valid, i.e. not null or the last node |
| 79 | + // on the slice. |
| 80 | + while fast != last { |
| 81 | + // Move the auxiliary pointer one step and check if we could move another step. |
| 82 | + fast_next = fast.and_then(|node| node.next.as_ref()); |
| 83 | + if fast_next == last { |
| 84 | + break; |
| 85 | + } |
| 86 | + // Move the slow pointer one step. |
| 87 | + slow = slow.and_then(|node| node.next.as_ref()); |
| 88 | + // Fast needs to move two steps. |
| 89 | + fast = fast_next.and_then(|node| node.next.as_ref()); |
| 90 | + } |
| 91 | + Some(Rc::new(RefCell::new(TreeNode { |
| 92 | + val: slow?.val, |
| 93 | + left: Self::slice_to_bst(first, slow), |
| 94 | + right: Self::slice_to_bst(slow?.next.as_ref(), last), |
| 95 | + }))) |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +// Tests. |
| 100 | +fn main() { |
| 101 | + let tests = [ |
| 102 | + (vec![3], 10, 1), |
| 103 | + (vec![3, 6, 7, 11], 8, 4), |
| 104 | + (vec![30, 11, 23, 4, 20], 5, 30), |
| 105 | + (vec![30, 11, 23, 4, 20], 6, 23), |
| 106 | + ( |
| 107 | + vec![ |
| 108 | + 332484035, 524908576, 855865114, 632922376, 222257295, 690155293, 112677673, |
| 109 | + 679580077, 337406589, 290818316, 877337160, 901728858, 679284947, 688210097, |
| 110 | + 692137887, 718203285, 629455728, 941802184, |
| 111 | + ], |
| 112 | + 823855818, |
| 113 | + 14, |
| 114 | + ), |
| 115 | + ]; |
| 116 | + for test in tests { |
| 117 | + unimplemented!(); |
| 118 | + } |
| 119 | + println!("No tests for this file!") |
| 120 | +} |
0 commit comments