1. Tree Data Structure#
- Definition of a Tree
- A tree is a data structure that must be connected and contain no circles.
- A single node is a valid tree. A collection of disconnected trees is a “forest”.
- A binary tree is a specific type where each node has at most two children.
- Tree Traversal Methods
- Traversal is the process of visiting all nodes in a tree.
- For binary trees, the three common methods are:
- Pre-order: Node, Left, Right.
- In-order: Left, Node, Right.
- Post-order: Left, Right, Node.
- An example:

- Pre-order: 1, 2, 5, 6, 3, 7
- In-order: 5, 2, 6, 1, 3, 7
- Post-order: 5, 6, 2, 7, 3, 1
2. Reconstructing a Tree from Traversal Sequences#
- Uniqueness of Tree Reconstruction
- A single traversal sequence (e.g., pre-order) is not sufficient to uniquely reconstruct a tree.
- A unique tree can be constructed if you are given the in-order sequence and either the pre-order or post-order sequence.
- Algorithm for Tree Reconstruction (from Pre-order and In-order)
- The first element in the pre-order sequence is the root of the current tree/subtree.
- Locate this root in the in-order sequence.
- Elements to the left of the root in the in-order sequence form the left subtree; elements to the right form the right subtree.
- Recursively apply this process to the left and right subtrees using the corresponding segments of the pre-order and in-order sequences.
- Code Implementation for Tree Reconstruction (with a tree)
import java.util.*;
class Tree {
private class Node {
int val;
Node lc, rc;
Node(int val, Node lc, Node rc) {
this.val = val;
this.lc = lc;
this.rc = rc;
}
}
private final Node root;
private Node buildTree(int[] pre, int[] inOrder, int[] idx,
int preL, int preR, int inL, int inR) {
if (preL > preR || inL > inR) {
return null;
}
int cur = pre[preL];
int cur_idx = idx[cur];
int left_size = cur_idx - inL;
Node lc = buildTree(pre, inOrder, idx,
preL + 1, preL + left_size,
inL, cur_idx - 1);
Node rc = buildTree(pre, inOrder, idx,
preL + left_size + 1, preR,
cur_idx + 1, inR);
return new Node(cur, lc, rc);
}
private void printPost(Node cur) {
if (cur == null) {
return;
}
printPost(cur.lc);
printPost(cur.rc);
System.out.print(cur.val + " ");
}
public void printPost() {
printPost(root);
}
public Tree(int[] pre, int[] inOrder, int[] idx) {
int n = pre.length;
root = buildTree(pre, inOrder, idx,
0, n - 1, 0, n - 1);
}
}
public class Traversal {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
while (t-- > 0) {
int n = in.nextInt();
int[] pre = new int[n];
int[] inOrder = new int[n];
int[] idx = new int[n + 1];
for (int i = 0; i < n; i++) {
pre[i] = in.nextInt();
}
for (int i = 0; i < n; i++) {
inOrder[i] = in.nextInt();
idx[inOrder[i]] = i;
}
Tree tree = new Tree(pre, inOrder, idx);
tree.printPost();
System.out.println();
}
in.close();
}
}
import java.util.*;
public class TraversalSim {
static void dfs(int[] pre, int[] inOrder, int[] idx,
int preL, int preR, int inL, int inR) {
if (preL > preR || inL > inR)
return;
int cur = pre[preL];
int cur_idx = idx[cur];
int left_size = cur_idx - inL;
dfs(pre, inOrder, idx,
preL + 1, preL + left_size,
inL, cur_idx - 1);
dfs(pre, inOrder, idx,
preL + left_size + 1, preR,
cur_idx + 1, inR);
System.out.print(cur + " ");
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
while (t-- > 0) {
int n = in.nextInt();
int[] pre = new int[n];
int[] inOrder = new int[n];
int[] idx = new int[n + 1];
for (int i = 0; i < n; i++) {
pre[i] = in.nextInt();
}
for (int i = 0; i < n; i++) {
inOrder[i] = in.nextInt();
idx[inOrder[i]] = i;
}
dfs(pre, inOrder, idx,
0, n - 1, 0, n - 1);
System.out.println();
}
in.close();
}
}
3. Reverse Polish Notation (Postfix Expression)#
- Expression Trees
- A tree representing a mathematical expression, with operators as internal nodes and operands as leaf nodes.
- Postfix Notation (Reverse Polish Notation)
- The sequence obtained by a post-order traversal of an expression tree (e.g.,
1 5 6 * + for 1 + 5 * 6).
- Evaluating Postfix Expressions with a Stack
- Postfix expressions can be evaluated efficiently in a single pass using a stack.
- Algorithm:
- Scan the expression from left to right.
- If an item is an operand (number), push it onto the stack.
- If an item is an operator, pop the top two operands, perform the operation, and push the result back onto the stack.
- The final result is the only number left on the stack.
- Code Implementation for Evaluating RPN
import java.util.*;
public class RPN {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Stack<Long> st = new Stack<>();
while (in.hasNext()) {
String s = in.next();
if (s.equals("+")) {
st.push(st.pop() + st.pop());
} else if (s.equals("-")) {
long a = st.pop();
long b = st.pop();
st.push(b - a);
} else if (s.equals("*")) {
st.push(st.pop() * st.pop());
} else if (s.equals("/")) {
long a = st.pop();
long b = st.pop();
st.push(b / a);
} else {
st.push(Long.valueOf(s));
}
}
System.out.println(st.pop());
in.close();
}
}
4. Validating a Binary Search Tree (BST)#
- Definition of a BST
- A tree where a node’s value is greater than all values in its left subtree and smaller than all values in its right subtree.
- Solution 1: In-order Traversal
- A key property of a valid BST is that its in-order traversal results in a strictly increasing sequence. This can be used for validation.
- Solution 2: Recursive Traversal with Bounds
- The recursive approach passes down an upper and lower bound for each node to validate against.
- For a left child, the upper bound becomes the parent’s value.
- For a right child, the lower bound becomes the parent’s value.
- Code Implementation for Validating BST by Recursion
import java.util.*;
class Tree {
private class Node {
final int val;
final int lc, rc;
Node(int val, int lc, int rc) {
this.val = val;
this.lc = lc;
this.rc = rc;
}
}
Node[] nodes;
public void iaddNode(int idx, int val, int l, int r) {
nodes[idx] = new Node(val, l, r);
}
public Tree(int n) {
nodes = new Node[n + 1];
nodes[0] = null;
}
private boolean isValid(Node cur, int min, int max) {
if (cur == null)
return true;
if (cur.val <= min || cur.val >= max)
return false;
return isValid(nodes[cur.lc], min, cur.val)
&& isValid(nodes[cur.rc], cur.val, max);
}
public boolean isValid() {
return isValid(nodes[1], Integer.MIN_VALUE, Integer.MAX_VALUE);
}
}
public class validBst {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
while (t-- > 0) {
int n = in.nextInt();
Tree tree = new Tree(n);
for (int i = 1; i <= n; i++) {
int v, l, r;
v = in.nextInt();
l = in.nextInt();
r = in.nextInt();
tree.iaddNode(i, v, l, r);
}
if (tree.isValid()) {
System.out.println("YES");
} else {
System.out.println("NO");
}
}
in.close();
}
}
5. Finding a Dynamic Cut-off Score#
- Problem Description
- Dynamically find the score of the $T$-th ranked student from a list of scores as new scores are added and $T$ changes.
- Proposed Solution: Two Heaps
- Min-Heap (“winners”): Stores the top $T$ scores. Its root is the cut-off score.
- Max-Heap (“others”): Stores all other scores.
- Logic of the Two-Heap Algorithm
- Add New Score: When a new score arrives, place it in the appropriate heap by comparing it to the current cut-off score (root of the min-heap).
- Adjust Heaps: Move elements between the heaps until the “winners” min-heap has exactly $T$ elements.
- Get Result: The root of the “winners” min-heap is always the current cut-off score.
- Small Trick for Max-Heap
- In Java, a max-heap can be created from a
PriorityQueue using Collections.reverseOrder() or by storing the negative of each value in a standard min-heap.
- Code Implementation for the Problem
import java.util.*;
public class Awards {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int w = in.nextInt();
PriorityQueue<Integer> winner = new PriorityQueue<>();
PriorityQueue<Integer> others =
new PriorityQueue<>(Collections.reverseOrder());
for (int i = 0; i < n; i++) {
int score = in.nextInt();
int planWin = (int) Math.max(1, (1l * (i + 1) * w) / 100);
if (winner.isEmpty()) {
others.add(score);
} else {
int smallest = winner.peek();
if (score > smallest) {
others.add(winner.poll());
winner.add(score);
} else {
others.add(score);
}
}
while (winner.size() < planWin) {
winner.add(others.poll());
}
System.out.print(winner.peek() + " ");
}
in.close();
}
}