Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions ConstructBTFromInorderAndPreorder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//
// ConstructBinaryTreeFromPreorder.swift
// DSA-Practice
//
// Created by Paridhi Malviya on 1/19/26.
//

class BinaryTreeFromInorderPreorder {

init() {
let preOrder = [3,9,20,15,7]
let inorder = [9,3,15,20,7]
// let _ = constructTreeUsingSubarrays(preOrder, inorder)
var inorderMap = Dictionary<Int, Int>()
for (index, element) in inorder.enumerated() {
inorderMap[element] = index
}
// return constructTreeUsingSubarrays(preorder, inorder)
let _ = helper(preOrder, inMap: inorderMap, inStart: 0, inEnd: inorder.count - 1)

}

/*
time compelxity - n recursive calls. O(n)
2. in each recursive call - we are doing n calls for searching the inorder root - O(n)
3. creating deep copies - O(n) Array(...)
2nd and 3rd needs O(n) time in each recursive call
So total time compelxity - O(n^2)

Space complexity - O(n^2)
n recursive calls. In each, creating four parts of the same array O(n)
*/
func constructTreeUsingSubarrays(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? {

if (preorder.count == 0) {
return nil
}
let rootVal = preorder[0]
let rootNode = TreeNode(val: rootVal, left: nil, right: nil)

var inorderRoot = -1
//find out the value in inorder array
for i in 0..<inorder.count {
if (inorder[i] == rootVal) {
inorderRoot = i
break
}
}

let inLeft = inorder[0..<inorderRoot] //span of inorder of left subtree
let inRight = inorder[(inorderRoot+1)..<(inorder.count)]
let preLeft = preorder[1..<1+inLeft.count]
let preRight = preorder[1+inLeft.count..<preorder.count]


rootNode.left = constructTreeUsingSubarrays(Array(preLeft), Array(inLeft))
rootNode.right = constructTreeUsingSubarrays(Array(preRight), Array(inRight))
return rootNode

}

/*
Time complexity - O(n)
space complexity - O(n)
*/
var preOrderIdx: Int = 0

//using pointers and map
func helper(_ preorder: [Int], inMap: Dictionary<Int,Int>, inStart: Int, inEnd: Int) -> TreeNode? {
if (inStart > inEnd) {
return nil
}
//logic
let rootVal = preorder[preOrderIdx]
let root = TreeNode(val: rootVal, left: nil, right: nil)
preOrderIdx = preOrderIdx + 1

let inRIdx = inMap[rootVal]!

root.left = helper(preorder, inMap: inMap, inStart: inStart, inEnd: inRIdx - 1)
root.right = helper(preorder, inMap: inMap, inStart: inRIdx + 1, inEnd: inEnd)
return root
}
}
159 changes: 159 additions & 0 deletions ValidateBinarySearchTree.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
//
// Validate binary search tree.swift
// DSA-Practice
//
// Created by Paridhi Malviya on 1/15/26.
//

/*
inorder traversal is sorted if it is BST.
inorder - left -> root -> right, right -> root -> left
preorder = root -> left -> right , root -> right -> left
postorder = left - right - root, right - left - root

to check if it is valid bst or not -> Do inorder, if sorted, it's BST
*/

class TreeNode {
var left: TreeNode?
var right: TreeNode?
var val: Int

init(val: Int, left: TreeNode?, right: TreeNode?) {
self.val = val
self.left = left
self.right = right
}
}

class BinarySearchTree {

var prev: TreeNode?
var flag: Bool

init() {
flag = true
}

func inorderTraversal(_ root: TreeNode?) -> [Int] {
//base
if (root == nil) {
return []
}
let leftTraversal: [Int] = inorderTraversal(root?.left)
let rightTraversal = inorderTraversal(root?.right)
return leftTraversal + [root!.val] + rightTraversal
}

func isValidBST(root: TreeNode?) -> Bool {
self.flag = true
inorderToCheckValidBST(root)
return flag
}

func inorderToCheckValidBST(_ root: TreeNode?) {
if (root == nil) {
return
}
if (!flag) {
return
}
inorderToCheckValidBST(root?.left)
if (prev != nil && root!.val <= prev!.val) {
//breach
flag = false
}
prev = root
inorderToCheckValidBST(root?.right)
}

//without flag bool
func isValidBSTWithoutFLag(root: TreeNode?) -> Bool {
return inorderToCheckValidBSTBooleanBased(root)
}

//boolean based recursion
func inorderToCheckValidBSTBooleanBased(_ root: TreeNode?) -> Bool {
if (root == nil) {
return true
}
let isLeftValid: Bool = inorderToCheckValidBSTBooleanBased(root?.left)
if (!isLeftValid) {
return false
}

if (prev != nil && root!.val <= prev!.val) {
//breach
return false
}
prev = root
return inorderToCheckValidBSTBooleanBased(root?.right)
}
}

extension BinarySearchTree {
//Without previous variable

func inOrderWithoutPreviousVariable(_ root: TreeNode?) -> Bool {
if (root == nil) {
return true
}

let isLeftValid = inOrderWithoutPreviousVariable(root?.left)
let isRightValid = inOrderWithoutPreviousVariable(root?.right)

if (root!.left != nil && root!.val < root!.left!.val) {
return false
}

if (root!.right != nil && root!.val > root!.right!.val) {
return false
}

return isLeftValid && isRightValid
}
}
/*
at every node, we can have a potential range. Each element should lie in that range. If there is a breach, then it's not a valid BST.
start recursion from the root.
IF we keep max and min in global then,
//if going left, then max = root.val, minimum = earlier minimum only

If I go right , then minimum will be root.val. maximum = earlier maximum
Every node should have it's own minimum and maximum.

time complexity -> each node will be visited once so O(n)
*/
class BinarySearchTree2 {

var flag = true
var node: TreeNode?
init() {

let isValid = validateBinarySearchUsingRange(root: node, min: Int.min, max: Int.max)
print("isValid \(isValid)")
}

func validateBinarySearchUsingRange(root: TreeNode?, min: Int, max: Int) -> Bool {

if (root == nil) {
return true
}

//checking that the node is in the range at preorder level. We can check the same at postorder and inorder level.
/*minimum and maximum are in the recursion stack. Whenever root is coming out, it's comin gout with it's minimum and maximum. It will remain same at the preorder, postorder and inorder*/
if (root!.val >= max && root!.val <= min) {
return false
}

let isLeftValid = validateBinarySearchUsingRange(root: root?.left, min: min, max: root!.val)

//stopping the right side recursive calls id the flag is false.
if (!isLeftValid) {
return false
}
let isRightValid = validateBinarySearchUsingRange(root: root?.right, min: root!.val, max: max)

return isLeftValid && isRightValid
}
}