Reputation: 2953
I need to minimize the memory consumption and the execution time of a function that calculates the Range Sum of Binary Search Tree (https://leetcode.com/problems/range-sum-of-bst/).
The current results I am having are:
Runtime: 88 ms, faster than 69.00% of Go online submissions for Range Sum of BST.
Memory Usage: 7.9 MB, less than 5.67% of Go online submissions for Range Sum of BST.
My current code:
func rangeSumBST(root *TreeNode, min int, max int) int {
sum := 0
arr := []*TreeNode{root}
var node *TreeNode
for len(arr) > 0 {
node = arr[len(arr)-1]
arr = arr[:len(arr)-1]
if node.Val >= min && node.Val <= max {
sum += node.Val
}
if node.Left != nil && node.Val > min {
arr = append(arr, node.Left)
}
if node.Right != nil && node.Val < max {
arr = append(arr, node.Right)
}
}
return sum
}
I tried to solve the problem recursively, which was elegant but of course slower and more memory hungry than iterative solution.
The iterative solution I have is as lean and simple as I possibly can make it. I declare and reuse the node
variable instead of declaring it inside of the for loop. I add nodes to the end of the slice instead of beginning.
What else can I do to make it faster and use less memory? Or is there a more efficient algorithm? Or is it that Leetcode measuring the execution time and memory consumption somehow incorrectly?
Upvotes: 0
Views: 423
Reputation: 1979
Since it is a BST you can do in O(1) space complexity using Inorder Morris traversal for BST, you cannot do better than O(N) time complexity for single queries unless you have some kind of preprocessing in the tree itself. Your current implementation is using a stack so your current space complexity is O(N) in worst case, when tree is basically a path.
Implementation in Go (was able to beat 99%):
func rangeSumBST(root *TreeNode, min int, max int) int {
if root == nil {
return 0
}
var pre *TreeNode
curr := root
sum := 0
for curr != nil {
if curr.Left == nil {
if curr.Val >= min && curr.Val <= max {
sum += curr.Val
}
if curr.Val > max {
break
}
curr = curr.Right
} else {
pre = curr.Left
for pre.Right != nil && pre.Right != curr {
pre = pre.Right
}
if pre.Right == nil {
pre.Right = curr
curr = curr.Left
} else {
pre.Right = nil
if curr.Val >= min && curr.Val <= max {
sum += curr.Val
}
if curr.Val > max {
break
}
curr = curr.Right
}
}
}
return sum
}
Time complexity: O(Number of nodes)
Space complexity: O(1)
Note: Somehow it doesn't show any improvement in memory performance, maybe because the tests are not enough and leetcode is known to show old statistics of previously submitted solutions when tests were not too big.
Upvotes: 1