Repository: vaskoz/dailycodingproblem-go (go)

Issue:
Day 93
Good morning! Here's your coding interview problem for today.

This problem was asked by Apple.

Given a tree, find the largest tree/subtree that is a BST.

Given a tree, return the size of the largest tree/subtree that is a BST.

Pull request description:
Day93
Resolves #196.

Patch:
diff --git a/README.md b/README.md
index 2636fd1..01a7760 100644
--- a/README.md
+++ b/README.md
@@ -102,6 +102,7 @@ problems from
 * [Day 90](https://github.com/vaskoz/dailycodingproblem-go/issues/189)
 * [Day 91](https://github.com/vaskoz/dailycodingproblem-go/issues/192)
 * [Day 92](https://github.com/vaskoz/dailycodingproblem-go/issues/194)
+* [Day 93](https://github.com/vaskoz/dailycodingproblem-go/issues/196)
 * [Day 94](https://github.com/vaskoz/dailycodingproblem-go/issues/197)
 * [Day 95](https://github.com/vaskoz/dailycodingproblem-go/issues/198)
 * [Day 96](https://github.com/vaskoz/dailycodingproblem-go/issues/200)
diff --git a/day93/problem.go b/day93/problem.go
new file mode 100644
index 0000000..ed6d468
--- /dev/null
+++ b/day93/problem.go
@@ -0,0 +1,84 @@
+package day93
+
+// BinaryTree is a binary tree: left & right children.
+type BinaryTree struct {
+	Value       int
+	Left, Right *BinaryTree
+}
+
+// TreeInfo contains information from a given subtree.
+type TreeInfo struct {
+	IsBST  bool
+	Min    int
+	Max    int
+	Size   int
+	Ans    int
+	AnsPtr *BinaryTree
+}
+
+// MaxInt is the largest int.
+const MaxInt = int(^uint(0) >> 1)
+
+// MinInt is the smallest int.
+const MinInt = -MaxInt - 1
+
+// FindLargestBST will return a pointer to the root of the
+// largest BST in the binary tree.
+// Runs in O(N) time with no extra space.
+func FindLargestBST(tree *BinaryTree) *BinaryTree {
+	res := sizeOfLargestBST(tree)
+	return res.AnsPtr
+}
+
+// SizeOfLargestBST will return the number of nodes in the
+// largest BST in the binary tree.
+// Runs in O(N) time with no extra space.
+func SizeOfLargestBST(tree *BinaryTree) int {
+	res := sizeOfLargestBST(tree)
+	return res.Ans
+}
+
+func sizeOfLargestBST(tree *BinaryTree) TreeInfo {
+	if tree == nil {
+		return TreeInfo{IsBST: true, Min: MaxInt, Max: MinInt, Size: 0, Ans: 0}
+	}
+	if tree.Left == nil && tree.Right == nil {
+		return TreeInfo{IsBST: true, Min: tree.Value, Max: tree.Value, Size: 1, Ans: 1}
+	}
+	left := sizeOfLargestBST(tree.Left)
+	right := sizeOfLargestBST(tree.Right)
+	var info TreeInfo
+	info.Size = 1 + left.Size + right.Size
+	if left.IsBST && right.IsBST && left.Max < tree.Value && right.Min > tree.Value {
+		info.Min = min(left.Min, min(right.Min, tree.Value))
+		info.Max = max(right.Max, max(left.Max, tree.Value))
+		info.Ans = info.Size
+		info.AnsPtr = tree
+		info.IsBST = true
+		return info
+	}
+	if left.Ans > right.Ans {
+		info.Ans = left.Ans
+		info.AnsPtr = left.AnsPtr
+	} else {
+		info.Ans = right.Ans
+		info.AnsPtr = right.AnsPtr
+	}
+	info.Ans = max(left.Ans, right.Ans)
+	info.IsBST = false
+	return info
+}
+
+func min(a, b int) int {
+	if a < b {
+		return a
+	}
+	return b
+}
+
+func max(a, b int) int {
+	if a > b {
+		return a
+	}
+	return b
+}


Test patch:
diff --git a/day93/problem_test.go b/day93/problem_test.go
new file mode 100644
index 0000000..fa829e2
--- /dev/null
+++ b/day93/problem_test.go
@@ -0,0 +1,102 @@
+package day93
+
+import "testing"
+
+var testcases = []struct {
+	tree           *BinaryTree
+	largestBSTSize int
+	largestBST     *BinaryTree
+}{
+	{&BinaryTree{
+		Value: 60,
+		Left: &BinaryTree{
+			Value: 65,
+			Left: &BinaryTree{
+				Value: 50,
+				Left:  nil,
+				Right: nil,
+			},
+			Right: nil,
+		},
+		Right: &BinaryTree{
+			Value: 70,
+			Left:  nil,
+			Right: nil,
+		},
+	}, 2, nil},
+	{&BinaryTree{
+		Value: 60,
+		Left: &BinaryTree{
+			Value: 90,
+			Left:  nil,
+			Right: nil,
+		},
+		Right: &BinaryTree{
+			Value: 65,
+			Left:  nil,
+			Right: &BinaryTree{
+				Value: 70,
+				Left:  nil,
+				Right: nil,
+			},
+		},
+	}, 2, nil},
+	{&BinaryTree{
+		Value: 60,
+		Left: &BinaryTree{
+			Value: 40,
+			Left:  nil,
+			Right: nil,
+		},
+		Right: &BinaryTree{
+			Value: 65,
+			Left:  nil,
+			Right: &BinaryTree{
+				Value: 70,
+				Left:  nil,
+				Right: nil,
+			},
+		},
+	}, 4, nil},
+}
+
+func answerKey() {
+	testcases[0].largestBST = testcases[0].tree.Left
+	testcases[1].largestBST = testcases[1].tree.Right
+	testcases[2].largestBST = testcases[2].tree
+}
+
+func TestSizeOfLargestBST(t *testing.T) {
+	t.Parallel()
+	for _, tc := range testcases {
+		if result := SizeOfLargestBST(tc.tree); result != tc.largestBSTSize {
+			t.Errorf("Expected %v got %v", tc.largestBSTSize, result)
+		}
+	}
+}
+
+func BenchmarkSizeOfLargestBST(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, tc := range testcases {
+			SizeOfLargestBST(tc.tree)
+		}
+	}
+}
+
+func TestFindLargestBST(t *testing.T) {
+	answerKey()
+	t.Parallel()
+	for _, tc := range testcases {
+		if result := FindLargestBST(tc.tree); result != tc.largestBST {
+			t.Errorf("Expected %v got %v", tc.largestBST, result)
+		}
+	}
+}
+
+func BenchmarkFindLargestBST(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, tc := range testcases {
+			FindLargestBST(tc.tree)
+		}
+	}
+}