Skip to content

Commit 3942f6e

Browse files
committed
Validate Binary Search Tree
1 parent 2fb0e5b commit 3942f6e

File tree

2 files changed

+287
-0
lines changed

2 files changed

+287
-0
lines changed
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
package validatebinarysearchtree
2+
3+
import "testing"
4+
5+
func TestIsValidBST(t *testing.T) {
6+
tests := []struct {
7+
name string
8+
root *TreeNode
9+
want bool
10+
}{
11+
{
12+
name: "example 1: [2,1,3]",
13+
// 2
14+
// / \
15+
// 1 3
16+
root: &TreeNode{
17+
Val: 2,
18+
Left: &TreeNode{Val: 1},
19+
Right: &TreeNode{Val: 3},
20+
},
21+
want: true,
22+
},
23+
{
24+
name: "example 2: [5,1,4,null,null,3,6]",
25+
// 5
26+
// / \
27+
// 1 4
28+
// / \
29+
// 3 6
30+
root: &TreeNode{
31+
Val: 5,
32+
Left: &TreeNode{Val: 1},
33+
Right: &TreeNode{
34+
Val: 4,
35+
Left: &TreeNode{Val: 3},
36+
Right: &TreeNode{Val: 6},
37+
},
38+
},
39+
want: false,
40+
},
41+
{
42+
name: "single node",
43+
// 1
44+
root: &TreeNode{Val: 1},
45+
want: true,
46+
},
47+
{
48+
name: "nil root",
49+
root: nil,
50+
want: true,
51+
},
52+
{
53+
name: "left child equal to parent",
54+
// 2
55+
// /
56+
// 2
57+
root: &TreeNode{
58+
Val: 2,
59+
Left: &TreeNode{Val: 2},
60+
},
61+
want: false,
62+
},
63+
{
64+
name: "right child equal to parent",
65+
// 2
66+
// \
67+
// 2
68+
root: &TreeNode{
69+
Val: 2,
70+
Right: &TreeNode{Val: 2},
71+
},
72+
want: false,
73+
},
74+
{
75+
name: "valid larger tree",
76+
// 10
77+
// / \
78+
// 5 15
79+
// / \ / \
80+
// 3 7 13 20
81+
root: &TreeNode{
82+
Val: 10,
83+
Left: &TreeNode{
84+
Val: 5,
85+
Left: &TreeNode{Val: 3},
86+
Right: &TreeNode{Val: 7},
87+
},
88+
Right: &TreeNode{
89+
Val: 15,
90+
Left: &TreeNode{Val: 13},
91+
Right: &TreeNode{Val: 20},
92+
},
93+
},
94+
want: true,
95+
},
96+
{
97+
name: "left subtree value greater than ancestor",
98+
// 15 > 10 but 15 is in left subtree
99+
// 10
100+
// / \
101+
// 5 20
102+
// / \
103+
// 3 8
104+
// \
105+
// 15
106+
root: &TreeNode{
107+
Val: 10,
108+
Left: &TreeNode{
109+
Val: 5,
110+
Left: &TreeNode{Val: 3},
111+
Right: &TreeNode{
112+
Val: 8,
113+
Right: &TreeNode{Val: 15},
114+
},
115+
},
116+
Right: &TreeNode{Val: 20},
117+
},
118+
want: false,
119+
},
120+
{
121+
name: "right subtree value less than ancestor",
122+
// 6 < 10 but 6 is in right subtree
123+
// 10
124+
// / \
125+
// 5 15
126+
// / \
127+
// 6 20
128+
// /
129+
// 18
130+
root: &TreeNode{
131+
Val: 10,
132+
Left: &TreeNode{Val: 5},
133+
Right: &TreeNode{
134+
Val: 15,
135+
Left: &TreeNode{Val: 6},
136+
Right: &TreeNode{
137+
Val: 20,
138+
Left: &TreeNode{Val: 18},
139+
},
140+
},
141+
},
142+
want: false,
143+
},
144+
{
145+
name: "only left children",
146+
// 5
147+
// /
148+
// 3
149+
// /
150+
// 1
151+
root: &TreeNode{
152+
Val: 5,
153+
Left: &TreeNode{
154+
Val: 3,
155+
Left: &TreeNode{
156+
Val: 1,
157+
},
158+
},
159+
},
160+
want: true,
161+
},
162+
{
163+
name: "only right children",
164+
// 1
165+
// \
166+
// 3
167+
// \
168+
// 5
169+
root: &TreeNode{
170+
Val: 1,
171+
Right: &TreeNode{
172+
Val: 3,
173+
Right: &TreeNode{
174+
Val: 5,
175+
},
176+
},
177+
},
178+
want: true,
179+
},
180+
{
181+
name: "negative values valid",
182+
// 0
183+
// / \
184+
// -5 5
185+
root: &TreeNode{
186+
Val: 0,
187+
Left: &TreeNode{Val: -5},
188+
Right: &TreeNode{Val: 5},
189+
},
190+
want: true,
191+
},
192+
{
193+
name: "negative values invalid",
194+
// -15 > -20 but -15 is in right subtree of root -10
195+
// -10
196+
// / \
197+
// -20 0
198+
// /
199+
// -15
200+
root: &TreeNode{
201+
Val: -10,
202+
Left: &TreeNode{Val: -20},
203+
Right: &TreeNode{
204+
Val: 0,
205+
Left: &TreeNode{Val: -15},
206+
},
207+
},
208+
want: false,
209+
},
210+
{
211+
name: "min and max int values",
212+
// 0
213+
// / \
214+
// -2147483648 2147483647
215+
root: &TreeNode{
216+
Val: 0,
217+
Left: &TreeNode{Val: -2147483648},
218+
Right: &TreeNode{Val: 2147483647},
219+
},
220+
want: true,
221+
},
222+
}
223+
224+
for _, tt := range tests {
225+
t.Run(tt.name, func(t *testing.T) {
226+
got := isValidBST(tt.root)
227+
if got != tt.want {
228+
t.Errorf("isValidBST() = %v, want %v", got, tt.want)
229+
}
230+
})
231+
}
232+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// 98. Validate Binary Search Tree
2+
// Topics: 'Binary Search Tree', 'Tree', 'Binary Tree', 'Depth-First Search'
3+
// Level: 'Medium'
4+
5+
// Given the root of a binary tree, determine if it is a valid binary search tree (BST).
6+
7+
// A valid BST is defined as follows:
8+
9+
// The left
10+
11+
// of a node contains only nodes with keys strictly less than the node's key.
12+
// The right subtree of a node contains only nodes with keys strictly greater than the node's key.
13+
// Both the left and right subtrees must also be binary search trees.
14+
15+
// Example 1:
16+
17+
// Input: root = [2,1,3]
18+
// Output: true
19+
20+
// Example 2:
21+
22+
// Input: root = [5,1,4,null,null,3,6]
23+
// Output: false
24+
// Explanation: The root node's value is 5 but its right child's value is 4.
25+
26+
// Constraints:
27+
28+
// The number of nodes in the tree is in the range [1, 104].
29+
// -231 <= Node.val <= 231 - 1
30+
31+
package validatebinarysearchtree
32+
33+
func isValidBST(root *TreeNode) bool {
34+
return valid(root, nil, nil)
35+
}
36+
37+
func valid(root *TreeNode, min, max *int) bool {
38+
if root == nil {
39+
return true
40+
}
41+
if min != nil && root.Val <= *min {
42+
return false
43+
}
44+
if max != nil && root.Val >= *max {
45+
return false
46+
}
47+
48+
return valid(root.Left, min, &root.Val) && valid(root.Right, &root.Val, max)
49+
}
50+
51+
type TreeNode struct {
52+
Right *TreeNode
53+
Left *TreeNode
54+
Val int
55+
}

0 commit comments

Comments
 (0)