Skip to content

Commit 615920b

Browse files
committed
largest BST subtree
1 parent e7d6889 commit 615920b

File tree

4 files changed

+258
-90
lines changed

4 files changed

+258
-90
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2016 Baidu Inc. All rights reserved.
2+
3+
package joshua.leetcode.binarytree.bst;
4+
5+
import joshua.leetcode.binarytree.TreeNode;
6+
7+
/**
8+
* 333. Largest BST Subtree <br/>
9+
* <p/>
10+
* <a href="https://leetcode.com/problems/largest-bst-subtree/">leetcode link</a>
11+
*
12+
* @author Jiang Yong ([email protected])
13+
*/
14+
public abstract class LargestBSTSubtree {
15+
16+
/**
17+
* Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where largest means subtree with largest number of nodes in it.
18+
* <p/>
19+
* Note:
20+
* A subtree must include all of its descendants.
21+
* Here's an example:
22+
* 10
23+
* / \
24+
* 5 15
25+
* / \ \
26+
* 1 8 7
27+
* The Largest BST Subtree in this case is the highlighted one.
28+
* The return value is the subtree's size, which is 3.
29+
*/
30+
public abstract int largestBSTSubtree(TreeNode root);
31+
32+
/**
33+
*
34+
*
35+
*/
36+
public static class Solution1 extends LargestBSTSubtree {
37+
38+
private int largestBSTSize = 0;
39+
40+
@Override
41+
public int largestBSTSubtree(TreeNode root) {
42+
largestBSTSize = 0;
43+
if (root != null) {
44+
traverseNode(root);
45+
}
46+
return largestBSTSize;
47+
}
48+
49+
private NodeInfo traverseNode(TreeNode root) {
50+
if (root.left == null && root.right == null) {
51+
largestBSTSize = Math.max(largestBSTSize, 1);
52+
return new NodeInfo(root.val, root.val, true, 1);
53+
}
54+
NodeInfo infoFromLeft = root.left != null ? traverseNode(root.left) : null;
55+
NodeInfo infoFromRight = root.right != null ? traverseNode(root.right) : null;
56+
if (infoFromLeft != null) {
57+
if (!infoFromLeft.isBST || root.val <= infoFromLeft.largestInSubTree) {
58+
return new NodeInfo(0, 0, false, 0);
59+
}
60+
}
61+
if (infoFromRight != null) {
62+
if (!infoFromRight.isBST || root.val >= infoFromRight.smallestInSubTree) {
63+
return new NodeInfo(0, 0, false, 0);
64+
}
65+
}
66+
int subTreeSmallest = infoFromLeft != null ? infoFromLeft.smallestInSubTree : root.val;
67+
int subTreeLargest = infoFromRight != null ? infoFromRight.largestInSubTree : root.val;
68+
69+
70+
int BSTSize = 1;
71+
if (infoFromLeft != null) {
72+
BSTSize += infoFromLeft.size;
73+
}
74+
if (infoFromRight != null) {
75+
BSTSize += infoFromRight.size;
76+
}
77+
largestBSTSize = Math.max(largestBSTSize, BSTSize);
78+
return new NodeInfo(subTreeSmallest, subTreeLargest, true, BSTSize);
79+
}
80+
81+
class NodeInfo {
82+
int smallestInSubTree;
83+
int largestInSubTree;
84+
int size;
85+
boolean isBST;
86+
87+
public NodeInfo(int smallestInSubTree, int largestInSubTree, boolean isBST, int size) {
88+
this.smallestInSubTree = smallestInSubTree;
89+
this.largestInSubTree = largestInSubTree;
90+
this.isBST = isBST;
91+
this.size = size;
92+
}
93+
}
94+
}
95+
}
Lines changed: 92 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,113 @@
11
package joshua.leetcode.binarytree.bst;
22

33
import joshua.leetcode.binarytree.TreeNode;
4+
import joshua.leetcode.solutiontag.Recursive;
45

56
/**
67
* 98 Validate Binary Search Tree
7-
*
8-
* @see <a href="https://leetcode.com/problems/validate-binary-search-tree/">leetcode link</a>
9-
* @author joy
108
*
9+
* @author joy
10+
* @see <a href="https://leetcode.com/problems/validate-binary-search-tree/">leetcode link</a>
1111
*/
1212
public abstract class ValidateBST {
1313

14-
/**
15-
* Given a binary tree, determine if it is a valid binary search tree (BST).
14+
/**
15+
* Given a binary tree, determine if it is a valid binary search tree (BST).
16+
* <p/>
17+
* Assume a BST is defined as follows:
18+
* <p/>
19+
* 1) The left subtree of a node contains only nodes with keys less than the node's key.
20+
* 2) The right subtree of a node contains only nodes with keys greater than the node's key.
21+
* 3) Both the left and right subtrees must also be binary search trees.
22+
*
23+
* @param root
24+
* @return
25+
*/
26+
public abstract boolean isValidBST(TreeNode root);
27+
28+
/**
29+
* 每个节点只遍历了一次, 类似DFS搜索。
30+
*
31+
* 时间复杂度 O(n)
32+
*/
33+
@Recursive
34+
static class Solution1 extends ValidateBST {
35+
36+
@Override
37+
public boolean isValidBST(TreeNode root) {
38+
if (root == null)
39+
return true;
40+
return recurValidate(root).result;
41+
}
1642

17-
Assume a BST is defined as follows:
18-
19-
1) The left subtree of a node contains only nodes with keys less than the node's key.
20-
2) The right subtree of a node contains only nodes with keys greater than the node's key.
21-
3) Both the left and right subtrees must also be binary search trees.
22-
23-
* @param root
24-
* @return
25-
*/
26-
public abstract boolean isValidBST(TreeNode root);
43+
private RecurResult recurValidate(TreeNode root) {
44+
if (root.left == null && root.right == null)
45+
return new RecurResult(root.val, root.val, true);
2746

28-
/**
29-
* recursive solution.
30-
* @author joy
31-
*
32-
*/
33-
static class Solution1 extends ValidateBST {
47+
RecurResult leftRes = root.left != null ? recurValidate(root.left) : null;
3448

35-
@Override
36-
public boolean isValidBST(TreeNode root) {
37-
if (root == null)
38-
return true;
39-
return recurValidate(root).result;
40-
}
49+
if (leftRes != null && (!leftRes.result || root.val <= leftRes.largest))
50+
return RecurResult.FALSE_RES;
4151

42-
private RecurResult recurValidate(TreeNode root) {
43-
if (root.left == null && root.right == null)
44-
return new RecurResult(root.val, root.val, true);
45-
46-
RecurResult leftRes = root.left != null ? recurValidate(root.left): null;
47-
48-
if (leftRes != null&& ( !leftRes.result|| root.val <= leftRes.largest))
49-
return RecurResult.FALSE_RES;
50-
51-
RecurResult rightRes = root.right != null ? recurValidate(root.right): null;
52-
if (rightRes != null
53-
&& (!rightRes.result || root.val >= rightRes.smallest ))
54-
return RecurResult.FALSE_RES;
52+
RecurResult rightRes = root.right != null ? recurValidate(root.right) : null;
53+
if (rightRes != null
54+
&& (!rightRes.result || root.val >= rightRes.smallest))
55+
return RecurResult.FALSE_RES;
5556

56-
return new RecurResult(rightRes != null ? rightRes.largest : root.val,
57-
leftRes != null ? leftRes.smallest: root.val,
58-
true);
59-
}
57+
return new RecurResult(rightRes != null ? rightRes.largest : root.val,
58+
leftRes != null ? leftRes.smallest : root.val,
59+
true);
60+
}
6061

61-
static class RecurResult {
62-
int largest;
63-
int smallest;
64-
boolean result;
62+
static class RecurResult {
63+
int largest;
64+
int smallest;
65+
boolean result;
6566

66-
static final RecurResult FALSE_RES = new RecurResult(0, 0, false);
67+
static final RecurResult FALSE_RES = new RecurResult(0, 0, false);
6768

68-
public RecurResult(int largest, int smallest, boolean result) {
69-
super();
70-
this.largest = largest;
71-
this.smallest = smallest;
72-
this.result = result;
73-
}
74-
}
69+
public RecurResult(int largest, int smallest, boolean result) {
70+
super();
71+
this.largest = largest;
72+
this.smallest = smallest;
73+
this.result = result;
74+
}
75+
}
76+
}
7577

76-
}
78+
/**
79+
* 对每个节点需要判断其是否大于左子树的最大值,以及右子树的最小值,因此每个节点的时间复杂度为log(n),
80+
* 总的平均复杂度为O(nlogn)
81+
*
82+
* 时间复杂度 O(nlogn)
83+
*/
84+
@Recursive
85+
static class Solution2 extends ValidateBST {
7786

87+
@Override
88+
public boolean isValidBST(TreeNode root) {
89+
if (root == null) {
90+
return true;
91+
}
92+
if (root.left != null) {
93+
TreeNode largestInLeft = root.left;
94+
while (largestInLeft.right != null) {
95+
largestInLeft = largestInLeft.right;
96+
}
97+
if (root.val <= largestInLeft.val) {
98+
return false;
99+
}
100+
}
101+
if (root.right != null) {
102+
TreeNode smallestInRight = root.right;
103+
while (smallestInRight.left != null) {
104+
smallestInRight = smallestInRight.left;
105+
}
106+
if (root.val >= smallestInRight.val) {
107+
return false;
108+
}
109+
}
110+
return isValidBST(root.left) && isValidBST(root.right);
111+
}
112+
}
78113
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package joshua.leetcode.binarytree.bst;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import joshua.leetcode.binarytree.TreeNode;
6+
import org.junit.Before;
7+
import org.junit.Test;
8+
9+
public class LargestBSTSubtreeTest {
10+
11+
LargestBSTSubtree solution;
12+
13+
@Before
14+
public void setUp() {
15+
solution = new LargestBSTSubtree.Solution1();
16+
}
17+
18+
@Test
19+
public void testSolution() {
20+
// TreeNode root1 = TreeNode.DeserializeTreeByLevelOrder(new String[]{"10", "5", "15", "1", "8", "#", "7"});
21+
// assertEquals(3, solution.largestBSTSubtree(root1));
22+
// TreeNode root2 = TreeNode.DeserializeTreeByLevelOrder(new String[]{"10", "5", "15", "1", "8", "#", "17"});
23+
// assertEquals(6, solution.largestBSTSubtree(root2));
24+
TreeNode root3 = TreeNode.DeserializeTreeByLevelOrder(new String[]{"10", "9", "15", "1", "8", "#", "17"});
25+
assertEquals(2, solution.largestBSTSubtree(root3));
26+
}
27+
28+
}
Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,57 @@
11
package joshua.leetcode.binarytree.bst;
22

3-
import static org.junit.Assert.*;
3+
import static org.junit.Assert.assertEquals;
44

55
import java.util.HashMap;
66

77
import joshua.leetcode.binarytree.TreeNode;
8-
98
import org.apache.commons.lang3.StringUtils;
109
import org.junit.Before;
1110
import org.junit.Test;
1211

1312
public class ValidateBSTTest {
1413

15-
HashMap<TreeNode,Boolean> testCases;
16-
17-
@Before
18-
public void setUp(){
19-
testCases=new HashMap<TreeNode,Boolean>();
20-
TreeNode root=TreeNode.DeserializeTreeByLevelOrder(new String[]{"0","-1"});
21-
testCases.put(root, true);
22-
root=TreeNode.DeserializeTreeByLevelOrder(new String[]{"1","#","1"});
23-
testCases.put(root, false);
24-
root=TreeNode.DeserializeTreeByLevelOrder(new String[]{"0","1"});
25-
testCases.put(root, false);
26-
//10,5,15,#,#,6,20
27-
root=TreeNode.DeserializeTreeByLevelOrder(new String[]{"10","5","15","#","#","6","20"});
28-
testCases.put(root, false);
29-
root=TreeNode.DeserializeTreeByLevelOrder(new String[]{"0","#","1"});
30-
testCases.put(root, true);
31-
root=TreeNode.DeserializeTreeByLevelOrder(new String[]{"5","14","#","1"});
32-
testCases.put(root, false);
33-
}
34-
35-
@Test
36-
public void testSolution1() {
37-
ValidateBST sol=new ValidateBST.Solution1();
38-
for(TreeNode root:testCases.keySet()){
39-
System.out.printf("testing [%s], ",StringUtils.join(TreeNode.SerializeTreeByLevelOrder(root),","));
40-
assertEquals(testCases.get(root),sol.isValidBST(root));
41-
System.out.println("passed.");
42-
}
43-
}
44-
45-
14+
HashMap<TreeNode, Boolean> testCases;
15+
16+
@Before
17+
public void setUp() {
18+
testCases = new HashMap<TreeNode, Boolean>();
19+
TreeNode root = TreeNode.DeserializeTreeByLevelOrder(new String[]{"0", "-1"});
20+
testCases.put(root, true);
21+
root = TreeNode.DeserializeTreeByLevelOrder(new String[]{"1", "#", "1"});
22+
testCases.put(root, false);
23+
root = TreeNode.DeserializeTreeByLevelOrder(new String[]{"0", "1"});
24+
testCases.put(root, false);
25+
//10,5,15,#,#,6,20
26+
root = TreeNode.DeserializeTreeByLevelOrder(new String[]{"10", "5", "15", "#", "#", "6", "20"});
27+
testCases.put(root, false);
28+
root = TreeNode.DeserializeTreeByLevelOrder(new String[]{"0", "#", "1"});
29+
testCases.put(root, true);
30+
root = TreeNode.DeserializeTreeByLevelOrder(new String[]{"5", "14", "#", "1"});
31+
testCases.put(root, false);
32+
}
33+
34+
@Test
35+
public void testSolution1() {
36+
ValidateBST sol = new ValidateBST.Solution1();
37+
for (TreeNode root : testCases.keySet()) {
38+
System.out.printf("testing [%s], ", StringUtils.join(TreeNode.SerializeTreeByLevelOrder(root), ","));
39+
assertEquals(testCases.get(root), sol.isValidBST(root));
40+
System.out.println("passed.");
41+
}
42+
}
43+
44+
45+
@Test
46+
public void testSolution2() {
47+
ValidateBST sol = new ValidateBST.Solution2();
48+
for (TreeNode root : testCases.keySet()) {
49+
System.out.printf("testing [%s], ", StringUtils.join(TreeNode.SerializeTreeByLevelOrder(root), ","));
50+
assertEquals(testCases.get(root), sol.isValidBST(root));
51+
System.out.println("passed.");
52+
}
53+
}
54+
55+
4656

4757
}

0 commit comments

Comments
 (0)