| 
 | 1 | +/*  | 
 | 2 | +	Reconstruct BST  | 
 | 3 | +	The pre-order traversal of a Binary Tree is a traversal technique that starts at the tree's root node and visits nodes in the following order:  | 
 | 4 | +		Current Node  | 
 | 5 | +		Left Subtree  | 
 | 6 | +		Right Subtree  | 
 | 7 | +
  | 
 | 8 | +  	Given a non-empty array of integers representing the pre-order traversal of a Binary Search Tree (BST),  | 
 | 9 | +	write a function that creates the relevant BST and returns its root node.  | 
 | 10 | +
  | 
 | 11 | +    The input array will contain the values of BST nodes in the order in which these nodes would be visited with a pre-order traversal.  | 
 | 12 | +
  | 
 | 13 | +	Sample Input: [10, 4, 2, 1, 5, 17, 19, 18]  | 
 | 14 | +	Sample Output:  | 
 | 15 | +	    10  | 
 | 16 | +      /    \  | 
 | 17 | +     4      17  | 
 | 18 | +   /   \      \  | 
 | 19 | +  2     5     19  | 
 | 20 | + /           /  | 
 | 21 | +1           18  | 
 | 22 | +
  | 
 | 23 | +	Explanation:  | 
 | 24 | +
  | 
 | 25 | +	Approach 1:  | 
 | 26 | +
  | 
 | 27 | +	The ReconstructBst function takes a slice preOrderTraversalValues which represents the pre-order traversal of a binary search tree.  | 
 | 28 | +	It reconstructs the BST using a recursive approach. Here's how the algorithm works:  | 
 | 29 | +
  | 
 | 30 | +	The base case is defined when the preOrderTraversalValues slice is empty, in which case it returns nil indicating an empty tree.  | 
 | 31 | +
  | 
 | 32 | +	The first element in the preOrderTraversalValues slice represents the current node value of the BST.  | 
 | 33 | +
  | 
 | 34 | +	The algorithm finds the index (rightSubTreeRootIdx) where the right subtree starts by iterating over the remaining elements in  | 
 | 35 | +	the preOrderTraversalValues slice and finding the first value greater than or equal to the current value.  | 
 | 36 | +
  | 
 | 37 | +	It recursively calls ReconstructBst on the sub-array representing the left subtree (preOrderTraversalValues[1:rightSubTreeRootIdx])  | 
 | 38 | +	to reconstruct the left subtree.  | 
 | 39 | +
  | 
 | 40 | +	It recursively calls ReconstructBst on the sub-array representing the right subtree (preOrderTraversalValues[rightSubTreeRootIdx:])  | 
 | 41 | +	to reconstruct the right subtree.  | 
 | 42 | +
  | 
 | 43 | +	Finally, it creates a new BST node with the current value, the reconstructed left subtree, and the reconstructed right subtree,  | 
 | 44 | +	and returns the node.  | 
 | 45 | +
  | 
 | 46 | +	The algorithm builds the BST in a top-down manner by dividing the pre-order traversal values into left and right subtrees.  | 
 | 47 | +	It constructs the left subtree first and then the right subtree.  | 
 | 48 | +
  | 
 | 49 | +	The time complexity of the algorithm is O(n^2) in the worst case, where n is the number of nodes in the BST.  | 
 | 50 | +
  | 
 | 51 | +
  | 
 | 52 | +	******************************************************************************************  | 
 | 53 | +
  | 
 | 54 | +	Approach 2:  | 
 | 55 | +
  | 
 | 56 | +	The ReconstructBst function takes a slice preOrderTraversalValues which represents the pre-order traversal of a binary search tree.  | 
 | 57 | +	It reconstructs the BST using a range-based approach. Here's how the algorithm works:  | 
 | 58 | +
  | 
 | 59 | +	The ReconstructBst function initializes a treeInfo struct to keep track of the current root index.  | 
 | 60 | +
  | 
 | 61 | +	The ReconstructBst function calls the reconstructBSTFromRange helper function, passing the minimum and maximum integer values  | 
 | 62 | +	as the initial range, the pre-order traversal values, and the treeInfo struct.  | 
 | 63 | +
  | 
 | 64 | +	The reconstructBSTFromRange function first checks if the current root index has reached the end of the pre-order traversal values.  | 
 | 65 | +	If so, it returns nil indicating an empty subtree.  | 
 | 66 | +
  | 
 | 67 | +	It retrieves the value of the current root from the pre-order traversal values.  | 
 | 68 | +
  | 
 | 69 | +	It checks if the root value is outside the valid range defined by the lower and upper bounds. If so, it returns  | 
 | 70 | +
  | 
 | 71 | +	The time complexity of the ReconstructBst function is O(n), where n is the number of nodes in the reconstructed BST.  | 
 | 72 | +	This is because the function processes each node exactly once.  | 
 | 73 | +
  | 
 | 74 | +	The space complexity of the ReconstructBst function is O(n), where n is the number of nodes in the reconstructed BST.  | 
 | 75 | +	This is because the function creates BST nodes and recursively calls itself to construct the left and right subtrees.  | 
 | 76 | +	The space complexity is determined by the height of the BST, which can be at most n in the worst case for a skewed BST.  | 
 | 77 | +*/  | 
 | 78 | +package main  | 
 | 79 | + | 
 | 80 | +import "math"  | 
 | 81 | + | 
 | 82 | +// BST represents a binary search tree node.  | 
 | 83 | +type BST struct {  | 
 | 84 | +	Value int  | 
 | 85 | +	Left  *BST  | 
 | 86 | +	Right *BST  | 
 | 87 | +}  | 
 | 88 | + | 
 | 89 | +// Approach 1: Time complexity O(n^2) Space O(n), where n is length of input array  | 
 | 90 | +// ReconstructBst takes a slice of integers representing the pre-order traversal of a BST and returns the reconstructed BST.  | 
 | 91 | +func ReconstructBst(preOrderTraversalValues []int) *BST {  | 
 | 92 | +	// Base case: If the pre-order traversal is empty, return nil indicating an empty tree.  | 
 | 93 | +	if len(preOrderTraversalValues) == 0 {  | 
 | 94 | +		return nil  | 
 | 95 | +	}  | 
 | 96 | + | 
 | 97 | +	// Get the current value from the pre-order traversal values.  | 
 | 98 | +	currentVal := preOrderTraversalValues[0]  | 
 | 99 | + | 
 | 100 | +	// Find the index where the right subtree starts by searching for the first value greater than or equal to the current value.  | 
 | 101 | +	rightSubTreeRootIdx := len(preOrderTraversalValues)  | 
 | 102 | +	for i := 1; i < len(preOrderTraversalValues); i++ {  | 
 | 103 | +		value := preOrderTraversalValues[i]  | 
 | 104 | +		if value >= currentVal {  | 
 | 105 | +			rightSubTreeRootIdx = i  | 
 | 106 | +			break  | 
 | 107 | +		}  | 
 | 108 | +	}  | 
 | 109 | + | 
 | 110 | +	// Recursively reconstruct the left and right subtrees by calling the ReconstructBst function on the appropriate sub-arrays.  | 
 | 111 | +	leftSubTree := ReconstructBst(preOrderTraversalValues[1:rightSubTreeRootIdx])  | 
 | 112 | +	rightSubTree := ReconstructBst(preOrderTraversalValues[rightSubTreeRootIdx:])  | 
 | 113 | + | 
 | 114 | +	// Create a new BST node with the current value and the reconstructed left and right subtrees.  | 
 | 115 | +	return &BST{Value: currentVal, Left: leftSubTree, Right: rightSubTree}  | 
 | 116 | +}  | 
 | 117 | + | 
 | 118 | + | 
 | 119 | +// Approach 2: Time complexity O(n) Space O(n), where n is length of input array  | 
 | 120 | + | 
 | 121 | +// treeInfo is a helper struct to keep track of the current root index during the reconstruction process.  | 
 | 122 | +type treeInfo struct {  | 
 | 123 | +	rootIdx int  | 
 | 124 | +}  | 
 | 125 | + | 
 | 126 | +// ReconstructBst takes a slice of integers representing the pre-order traversal of a BST and returns the reconstructed BST.  | 
 | 127 | +func ReconstructBst2(preOrderTraversalValues []int) *BST {  | 
 | 128 | +	// Create a treeInfo struct to keep track of the current root index.  | 
 | 129 | +	treeInfo := &treeInfo{rootIdx: 0}  | 
 | 130 | + | 
 | 131 | +	// Call the helper function to reconstruct the BST from the given range and return the result.  | 
 | 132 | +	return reconstructBSTFromRange(math.MinInt32, math.MaxInt32, preOrderTraversalValues, treeInfo)  | 
 | 133 | +}  | 
 | 134 | + | 
 | 135 | +// reconstructBSTFromRange reconstructs the BST recursively within the given range using the pre-order traversal values.  | 
 | 136 | +func reconstructBSTFromRange(lowerBound, upperBound int, preOrderTraversalValues []int, currentSubtreeInfo *treeInfo) *BST {  | 
 | 137 | +	// Check if the root index has reached the end of the pre-order traversal values. If so, return nil indicating an empty subtree.  | 
 | 138 | +	if currentSubtreeInfo.rootIdx == len(preOrderTraversalValues) {  | 
 | 139 | +		return nil  | 
 | 140 | +	}  | 
 | 141 | + | 
 | 142 | +	// Get the value of the current root from the pre-order traversal values.  | 
 | 143 | +	rootValue := preOrderTraversalValues[currentSubtreeInfo.rootIdx]  | 
 | 144 | + | 
 | 145 | +	// Check if the root value is out of the valid range defined by the lower and upper bounds. If so, return nil indicating an invalid subtree.  | 
 | 146 | +	if rootValue < lowerBound || rootValue >= upperBound {  | 
 | 147 | +		return nil  | 
 | 148 | +	}  | 
 | 149 | + | 
 | 150 | +	// Increment the root index to move to the next element in the pre-order traversal values.  | 
 | 151 | +	currentSubtreeInfo.rootIdx++  | 
 | 152 | + | 
 | 153 | +	// Recursively reconstruct the left subtree within the range (lowerBound, rootValue) using the updated root index.  | 
 | 154 | +	leftSubtree := reconstructBSTFromRange(lowerBound, rootValue, preOrderTraversalValues, currentSubtreeInfo)  | 
 | 155 | + | 
 | 156 | +	// Recursively reconstruct the right subtree within the range (rootValue, upperBound) using the updated root index.  | 
 | 157 | +	rightSubtree := reconstructBSTFromRange(rootValue, upperBound, preOrderTraversalValues, currentSubtreeInfo)  | 
 | 158 | + | 
 | 159 | +	// Create a new BST node with the current root value and the reconstructed left and right subtrees.  | 
 | 160 | +	return &BST{Value: rootValue, Left: leftSubtree, Right: rightSubtree}  | 
 | 161 | +}  | 
0 commit comments