← Home

109. Convert Sorted List to Binary Search Tree

LeetCode article · C++ solution
Website made by wuisabel-gif · Original C++ code by keineahnung2345
binary searchC++Markdown
109

This is one of those problems where the clean idea matters more than the amount of code. For 109. Convert Sorted List to Binary Search Tree, the solution in this repository is mainly a binary search solution.

Guide

What?

The first job is to translate the English prompt into state, transition, and stopping conditions. Instead of trying to be clever immediately, read the code as a sequence of questions:

  • What state are we keeping?
  • How do we move from one state to the next?
  • When do we know the answer is already determined?

For this file, the main tools are: binary search, two pointers, sliding window.

The notes already sitting in the source point us in the right direction:

  • recursion

Guide

When?

This pattern shows up when the brute force version has too many repeated checks, too many possible branches, or too much bookkeeping to do by hand. The accepted code reduces that pressure by storing exactly the information that remains useful later.

The important function names to track are sortedListToBST, sortedVectorToBST, convertListToBST.

Guide

Why?

The point of the implementation is not to make the code longer. It is to avoid doing the same thinking twice.

  • The final return is not magic; it is the invariant after the loops or recursion have finished doing their accounting.

Guide

How?

Walk through the solution in this order:

  1. Start from the smallest reliable state.
  2. Expand one legal move at a time.
  3. Cache, count, or merge information as soon as it becomes settled.
  4. Let the final stored value answer the original question.

The most important competitive-programming habit here is to trust the invariant. Once the invariant is right, the loops become much less scary.

Guide

Complexity

  • Time: O(n) to O(n log n), depending on the dominant loop or data structure operation
  • Space: O(n) in the usual case for auxiliary containers or recursion

Guide

C++ Solution

Your submission

The accepted solution

solution.cpp
01//recursion
02//Runtime: 40 ms, faster than 46.56% of C++ online submissions for Convert Sorted List to Binary Search Tree.
03//Memory Usage: 36.1 MB, less than 5.43% of C++ online submissions for Convert Sorted List to Binary Search Tree.
04/**
05 * Definition for singly-linked list.
06 * struct ListNode {
07 *     int val;
08 *     ListNode *next;
09 *     ListNode() : val(0), next(nullptr) {}
10 *     ListNode(int x) : val(x), next(nullptr) {}
11 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
12 * };
13 */
14/**
15 * Definition for a binary tree node.
16 * struct TreeNode {
17 *     int val;
18 *     TreeNode *left;
19 *     TreeNode *right;
20 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
21 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
22 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
23 * };
24 */
25class Solution {
26public:
27    TreeNode* sortedListToBST(ListNode* head) {
28        if(!head) return nullptr;
29        
30        ListNode* dummy = new ListNode(-1);
31        dummy->next = head;
32        
33        ListNode *slow = dummy, *fast = dummy;
34        ListNode *preslow;
35        
36        while(fast && fast->next){
37            preslow = slow;
38            slow = slow->next;
39            fast = fast->next->next;
40        }
41        
42        cout << preslow->val << ", " << slow->val << endl;
43        
44        //now slow is the midpoint(for odd-length list) or 
45        // the node before midpoint(for even-length list)
46        //preslow is the previous node of slow
47        
48        TreeNode* root = new TreeNode(slow->val);
49        
50        //cut the list's former part with the processed "slow"
51        preslow->next = nullptr;
52        //when slow==head, this node doesn't have left subtree
53        root->left = (slow == head) ? nullptr : sortedListToBST(head);
54        
55        root->right = sortedListToBST(slow->next);
56        
57        return root;
58    }
59};
60
61//recursion, without dummy
62//Runtime: 40 ms, faster than 46.56% of C++ online submissions for Convert Sorted List to Binary Search Tree.
63//Memory Usage: 32.9 MB, less than 5.43% of C++ online submissions for Convert Sorted List to Binary Search Tree.
64//time: O(NlogN)
65//in ith recursion(i starts from 1), we use (N/pow(2,i)) times to find middle point, do it pow(2,i-1) times
66//and we will do that for logN recursions, so it sums up to NlogN/2, which is O(NlogN)
67//space: O(logN)
68//recursion space used by "balanced" tree
69class Solution {
70public:
71    TreeNode* sortedListToBST(ListNode* head) {
72        if(!head) return nullptr;
73        
74        ListNode *slow = head, *fast = head;
75        ListNode *preslow = nullptr;
76        
77        while(fast && fast->next){
78            preslow = slow;
79            slow = slow->next;
80            fast = fast->next->next;
81        }
82        
83        // cout << (preslow ? preslow->val : -1) << ", " << slow->val << endl;
84        
85        //now slow is the midpoint(for odd-length list) or 
86        // the node after midpoint(for even-length list)
87        //preslow is the previous node of slow
88        
89        TreeNode* root = new TreeNode(slow->val);
90        
91        //cut the list's former part with the processed "slow"
92        //if slow is head, it means the list's length is 1,
93        //and preslow is nullptr
94        if(slow == head){
95            return root;
96        }
97        
98        //if slow != head, it has left subtree
99        preslow->next = nullptr;
100        
101        root->left = sortedListToBST(head);
102        
103        root->right = sortedListToBST(slow->next);
104        
105        return root;
106    }
107};
108
109//Approach 2: Recursion + Conversion to Array
110//use more space to reduce time complexity
111//Runtime: 40 ms, faster than 46.56% of C++ online submissions for Convert Sorted List to Binary Search Tree.
112//Memory Usage: 33.4 MB, less than 5.43% of C++ online submissions for Convert Sorted List to Binary Search Tree.
113//time: O(N), space: O(N)
114class Solution {
115public:
116    TreeNode* sortedVectorToBST(vector<int>& arr, int start, int end){
117        if(start > end) return nullptr;
118        
119        int mid = (start+end)>>1;
120        TreeNode* root = new TreeNode(arr[mid]);
121        
122        root->left = sortedVectorToBST(arr, start, mid-1);
123        root->right = sortedVectorToBST(arr, mid+1, end);
124        
125        return root;
126    }
127    
128    TreeNode* sortedListToBST(ListNode* head) {
129        vector<int> arr;
130        
131        while(head){
132            arr.push_back(head->val);
133            head = head->next;
134        }
135        
136        int n = arr.size();
137        
138        return sortedVectorToBST(arr, 0, n-1);
139    }
140};
141
142//Approach 3: Inorder Simulation
143//Runtime: 40 ms, faster than 46.56% of C++ online submissions for Convert Sorted List to Binary Search Tree.
144//Memory Usage: 33.1 MB, less than 5.43% of C++ online submissions for Convert Sorted List to Binary Search Tree.
145//time: O(N), space: O(logN)
146class Solution {
147public:
148    ListNode* head;
149    
150    TreeNode* convertListToBST(int start, int end){
151        if(start > end){
152            // cout << "return nullptr" << endl;
153            return nullptr;
154        }
155        
156        int mid = (start+end) >> 1;
157        
158        TreeNode* left = convertListToBST(start, mid-1);
159        
160        // cout << start << ", " << end << ", " << this->head->val << endl;
161        TreeNode* root = new TreeNode(this->head->val);
162        root->left = left;
163        
164        this->head = this->head->next;
165        
166        root->right = convertListToBST(mid+1, end);
167        
168        // cout << "return " << root->val << endl;
169        return root;
170    }
171    
172    TreeNode* sortedListToBST(ListNode* head) {
173        if(!head) return nullptr;
174        
175        int n = 0;
176        
177        ListNode* cur = head;
178        
179        while(cur){
180            ++n;
181            cur = cur->next;
182        }
183        
184        this->head = head;
185        
186        return convertListToBST(0, n-1);
187    }
188};

Cost

Complexity

Time
O(n) to O(n log n), depending on the dominant loop or data structure operation
Dominated by the main traversal, recursion, or data-structure operations in the code.
Space
O(n) in the usual case for auxiliary containers or recursion
Auxiliary state plus the answer structure where the problem requires one.