Cracking the Coding Interview, 4 Edition - 150 Programming Interview Questions and Solutions
Cracking the Coding Interview, 4 Edition - 150 Programming Interview Questions and Solutions
Cracking the Coding Interview, 4 Edition - 150 Programming Interview Questions and Solutions
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Solutions</strong> to Chapter 4 | Trees <strong>and</strong> Graphs<br />
4.7 You have two very large binary trees: T1, with millions of nodes, <strong>and</strong> T2, with hundreds<br />
of nodes. Create an algorithm to decide if T2 is a subtree of T1.<br />
SOLUTION<br />
pg 54<br />
Note that <strong>the</strong> problem here specifies that T1 has millions of nodes—this means that we<br />
should be careful of how much space we use. Let’s say, for example, T1 has 10 million<br />
nodes—this means that <strong>the</strong> data alone is about 40 mb. We could create a string representing<br />
<strong>the</strong> inorder <strong>and</strong> preorder traversals. If T2’s preorder traversal is a substring of T1’s preorder<br />
traversal, <strong>and</strong> T2’s inorder traversal is a substring of T1’s inorder traversal, <strong>the</strong>n T2 is a substring<br />
of T1. We can check this using a suffix tree. However, we may hit memory limitations<br />
because suffix trees are extremely memory intensive. If this become an issue, we can use an<br />
alternative approach.<br />
Alternative Approach: The treeMatch procedure visits each node in <strong>the</strong> small tree at most<br />
once <strong>and</strong> is called no more than once per node of <strong>the</strong> large tree. Worst case runtime is at<br />
most O(n * m), where n <strong>and</strong> m are <strong>the</strong> sizes of trees T1 <strong>and</strong> T2, respectively. If k is <strong>the</strong> number<br />
of occurrences of T2’s root in T1, <strong>the</strong> worst case runtime can be characterized as O(n + k * m).<br />
1 boolean containsTree(TreeNode t1, TreeNode t2) {<br />
2 if (t2 == null) return true; // The empty tree is always a subtree<br />
3 else return subTree(t1, t2);<br />
4 }<br />
5<br />
6 boolean subTree(TreeNode r1, TreeNode r2) {<br />
7 if (r1 == null)<br />
8 return false; // big tree empty & subtree still not found.<br />
9 if (r1.data == r2.data) {<br />
10 if (matchTree(r1,r2)) return true;<br />
11 }<br />
12 return (subTree(r1.left, r2) || subTree(r1.right, r2));<br />
13 }<br />
14<br />
15 boolean matchTree(TreeNode r1, TreeNode r2) {<br />
16 if (r2 == null && r1 == null)<br />
17 return true; // nothing left in <strong>the</strong> subtree<br />
18 if (r1 == null || r2 == null)<br />
19 return false; // big tree empty & subtree still not found<br />
20 if (r1.data != r2.data)<br />
21 return false; // data doesn’t match<br />
22 return (matchTree(r1.left, r2.left) &&<br />
23 matchTree(r1.right, r2.right));<br />
24 }<br />
25 }<br />
CareerCup.com<br />
1 3 0