The most complete preparation resource. Real questions from 2024β2026 papers with full Java solutions, DSA guide, theoretical Q&A, sub-problems, and a structured roadmap.
Follow this guide to get maximum value. Don't skip this β it tells you exactly where to start based on your level.
Scroll to the Preparation Roadmap section. Find your current level (Beginner / Intermediate / Advanced) and follow the weekly plan. Don't try to read everything at once.
Go to the DSA Guide section. Each topic has a concept explanation, a representative problem, and a complete Java solution. Study topics in the roadmap order.
Before tackling main questions, go to Sub-Problems. Each sub-problem is a building block. Master these smaller patterns to unlock harder questions.
Go to 2026 Exam or PYQs. Read the problem. Try to solve it for at least 20β30 minutes. Only then click to expand the solution and explanation.
Once you feel ready, go to the Mock Exam section. Set a 3-hour timer and solve 3 questions (Easy 30 min / Medium 60 min / Hard 90 min). This is the real test format.
In the DSA Guide, there's a complexity reference table. Memorize common TC/SC values. In the exam, always mention Time and Space Complexity β it matters for scoring.
Ctrl+F to search for any topic on this page instantly.
All 4 official questions from the 2026 HackWithInfy sample paper. Full Java solutions included.
v[i] β d[i] Γ (tβ1). You want to maximize the total taste points using at most M meals. You can buy the same food multiple times, but each repeat reduces its value by d[i].
Given an array, repeatedly extract the maximum element k times. β Understand PriorityQueue with custom comparator: new PriorityQueue<>((a,b) -> b-a)
Each pick changes the item's value. After picking item i, reduce v[i] by some delta. β Re-insert the modified item back into the heap.
If the heap's top value β€ 0, further picks only decrease total. β Break early to save time when all remaining options give β€ 0 taste.
import java.util.*; public class FoodStamps { // n = number of food types, m = total meal budget // v[i] = initial taste of food i, d[i] = decrease per repeat buy public static long maxTastePoints(int n, long m, long[] v, long[] d) { // Max-Heap stores [currentValue, decrement] sorted by currentValue desc PriorityQueue<long[]> heap = new PriorityQueue<>( (a, b) -> Long.compare(b[0], a[0]) ); // Only add food types with positive initial value for (int i = 0; i < n; i++) { if (v[i] > 0) heap.offer(new long[]{v[i], d[i]}); } long total = 0; for (long meal = 0; meal < m; meal++) { if (heap.isEmpty()) break; long[] top = heap.poll(); long curr = top[0], dec = top[1]; if (curr <= 0) break; // No more positive taste options total += curr; // Buy this food long next = curr - dec; // Next purchase gives less taste if (next > 0) heap.offer(new long[]{next, dec}); } return total; } public static void main(String[] args) { // Test Case: n=3, m=5, v=[5,7,9], d=[2,4,6] β Expected: 27 System.out.println(maxTastePoints(3, 5, new long[]{5,7,9}, new long[]{2,4,6})); // Trace: Pick 9βsum=9, Pick 7β16, Pick 5β21, Pick 3β24, Pick 3β27 β } }
O(M log N)O(N)Find MSS with no swaps. O(n) DP. cur = max(0, cur + a[i]); ans = max(ans, cur). This handles the base case perfectly.
Enumerate all O(nΒ²) subarrays [l..r]. For each, compute the sum. Used as a building block for k > 0.
For subarray [l..r], negatives inside can be swapped with positives outside. Sort both lists and greedily match smallest negative with largest positive outside.
import java.util.*; public class MSSWithSwaps { // Kadane's β used when k=0 static int kadane(int[] a) { int best = 0, cur = 0; for (int x : a) { cur = Math.max(0, cur + x); best = Math.max(best, cur); } return best; } public static int solve(int n, int k, int[] a) { if (k == 0) return kadane(a); int ans = 0; // Try every subarray [l..r] for (int l = 0; l < n; l++) { for (int r = l; r < n; r++) { // Collect negatives inside subarray (sorted ascending) List<Integer> inside = new ArrayList<>(); int subSum = 0; for (int i = l; i <= r; i++) { subSum += a[i]; if (a[i] < 0) inside.add(a[i]); } Collections.sort(inside); // Worst negatives first // Collect positives outside subarray (sorted descending) List<Integer> outside = new ArrayList<>(); for (int i = 0; i < n; i++) { if (i < l || i > r) if (a[i] > 0) outside.add(a[i]); } outside.sort(Collections.reverseOrder()); // Best positives first // Greedily swap: worst inside negative with best outside positive int swapped = 0, simSum = subSum; for (int s = 0; s < Math.min((long)k, Math.min(inside.size(), outside.size())); s++) { int gain = outside.get(s) - inside.get(s); if (gain <= 0) break; // No benefit simSum += gain; } ans = Math.max(ans, simSum); } } return ans; } public static void main(String[] args) { // k=1, a=[-1, 2, -3, 4, -5] β swap -5 into subarray [2..4], pick [4,2,-1] etc System.out.println(solve(5, 1, new int[]{-1,2,-3,4,-5})); } }
O(nΒ³ log n)O(n)Works for n β€ 500Sum of two numbers is even iff both are even or both are odd. (a+b) % 2 == 0 iff a%2 == b%2. This is the core condition.
Partition array into two groups. Find the two smallest elements in each group. This is O(n) β no sorting needed, just track min1 and min2.
For even group: ans = even_min1 + even_min2. For odd group: ans = odd_min1 + odd_min2. Final answer = min of both. If a group has fewer than 2 elements, skip it.
import java.util.*; public class LockAndParity { public static long minEvenPair(int n, long[] c) { // Separate into even-cost and odd-cost groups List<Long> evens = new ArrayList<>(); List<Long> odds = new ArrayList<>(); for (long cost : c) { if (cost % 2 == 0) evens.add(cost); else odds.add(cost); } long ans = Long.MAX_VALUE; // Find 2 minimums from each group β O(n) no sort needed for (List<Long> group : Arrays.asList(evens, odds)) { if (group.size() < 2) continue; long m1 = Long.MAX_VALUE, m2 = Long.MAX_VALUE; for (long x : group) { if (x <= m1) { m2 = m1; m1 = x; } else if (x < m2) { m2 = x; } } ans = Math.min(ans, m1 + m2); } return (ans == Long.MAX_VALUE) ? -1 : ans; } public static void main(String[] args) { // Locks: c=[3,6,4,9,2], expected: min even pair = 2+4=6 OR min odd pair = 3+9=12 β ans=6 System.out.println(minEvenPair(5, new long[]{3,6,4,9,2})); } }
O(N)O(N)O(1) space possibleBasic DFS from root with a visited array. Identify when a node is a leaf (no unvisited children).
DFS with a running maximum. At each step, only go deeper if next value β₯ current max. Classic "non-decreasing path" pattern.
Cost = sum of (yβx)Β² per edge. Track cumulative cost as you recurse. At leaf nodes, update global minimum.
import java.util.*; public class LayerSplitPath { static List<Integer>[] tree; static int[] layer; static long minCost = Long.MAX_VALUE; public static void dfs(int node, int parent, int maxLayer, long cost) { boolean isLeaf = true; for (int child : tree[node]) { if (child == parent) continue; isLeaf = false; // Non-decreasing layer constraint if (layer[child] >= maxLayer) { long edgeCost = (long)(layer[child] - layer[node]) * (layer[child] - layer[node]); dfs(child, node, layer[child], cost + edgeCost); } } if (isLeaf) { minCost = Math.min(minCost, cost); } } public static long solve(int n, int[] L, int[][] edges) { tree = new List[n + 1]; layer = L; for (int i = 1; i <= n; i++) tree[i] = new ArrayList<>(); for (int[] e : edges) { tree[e[0]].add(e[1]); tree[e[1]].add(e[0]); } minCost = Long.MAX_VALUE; dfs(1, -1, layer[1], 0); return minCost; } public static void main(String[] args) { // Tree: 1-2, 1-3, 2-4. Layers: [0,2,1,3]. Edges: [[1,2],[1,3],[2,4]] // Valid paths: 1β2β4 (layers 0,2,3 non-dec, cost=(2-0)Β²+(3-2)Β²=4+1=5) // Path 1β3 blocked: layer[3]=1 < layer[1]=0... but 1>0 so it's valid actually System.out.println(solve(4, new int[]{0,2,1,3}, new int[][]{{1,2},{1,3},{2,4}})); } }
O(N)O(N)All official questions from the 2024 and 2025 HackWithInfy sample papers with full Java solutions.
public class ArrayTypeQueries { public static int[] solve(int[] a, int[][] queries) { int n = a.length; // prefix[i] = count of even numbers in a[0..i-1] int[] prefix = new int[n + 1]; for (int i = 0; i < n; i++) prefix[i+1] = prefix[i] + (a[i] % 2 == 0 ? 1 : 0); int[] ans = new int[queries.length]; for (int q = 0; q < queries.length; q++) { int l = queries[q][0], r = queries[q][1]; ans[q] = prefix[r+1] - prefix[l]; // Count evens in [l,r] } return ans; } }
O(N)O(1)O(N)import java.util.*; public class GoodSubarray { public static long countGoodSubarrays(int[] a, int k) { Map<Integer,Integer> freq = new HashMap<>(); long count = 0; int left = 0; for (int right = 0; right < a.length; right++) { freq.merge(a[right], 1, Integer::sum); // Shrink window if element appears more than k times while (freq.get(a[right]) > k) { freq.merge(a[left], -1, Integer::sum); if (freq.get(a[left]) == 0) freq.remove(a[left]); left++; } count += right - left + 1; // All subarrays ending at 'right' } return count; } }
O(N)O(N)public class OilTank { public static int canCompleteCircuit(int[] gas, int[] cost) { int totalGas = 0, totalCost = 0, tank = 0, start = 0; for (int i = 0; i < gas.length; i++) { totalGas += gas[i]; totalCost += cost[i]; tank += gas[i] - cost[i]; if (tank < 0) { start = i + 1; tank = 0; } } return totalGas >= totalCost ? start : -1; } }
O(N)O(1)import java.util.*; public class ReduceSoldiers { public static int stepsToOne(int n) { // BFS: how many steps to reduce n to 1 // Each step: n β n/2 if even, n β (n-1)/2 if odd (count the odd one) Queue<Integer> queue = new LinkedList<>(); Set<Integer> visited = new HashSet<>(); queue.offer(n); visited.add(n); int steps = 0; while (!queue.isEmpty()) { int size = queue.size(); while (size-- > 0) { int curr = queue.poll(); if (curr == 1) return steps; // Next states depend on parity int[] nexts = (curr % 2 == 0) ? new int[]{curr/2} : new int[]{(curr-1)/2, (curr+1)/2}; for (int nx : nexts) if (nx >= 1 && visited.add(nx)) queue.offer(nx); } steps++; } return steps; } }
O(log N)O(log N)import java.util.*; public class InvasionGrid { static int[][] DIRS = {{0,1},{0,-1},{1,0},{-1,0}}; public static int[][] minInvasionTime(char[][] grid) { int R = grid.length, C = grid[0].length; int[][] dist = new int[R][C]; for (int[] row : dist) Arrays.fill(row, -1); Queue<int[]> q = new LinkedList<>(); // Add ALL invasion sources to BFS queue at time 0 for (int i = 0; i < R; i++) for (int j = 0; j < C; j++) if (grid[i][j] == 'I') { dist[i][j] = 0; q.offer(new int[]{i, j}); } while (!q.isEmpty()) { int[] cur = q.poll(); for (int[] d : DIRS) { int nr = cur[0]+d[0], nc = cur[1]+d[1]; if (nr>=0 && nr<R && nc>=0 && nc<C && grid[nr][nc]!='#' && dist[nr][nc]==-1) { dist[nr][nc] = dist[cur[0]][cur[1]] + 1; q.offer(new int[]{nr, nc}); } } } return dist; // dist[i][j] = min turns for invasion to reach (i,j) } }
O(NΓM)O(NΓM)import java.util.*; public class ExpertNumber { public static int mexOperations(int[] a) { Arrays.sort(a); int ops = 0, mex = 0; int i = 0; while (i < a.length) { if (a[i] == mex) { // Found an element equal to current MEX β remove it i++; mex++; ops++; } else if (a[i] < mex) { i++; // Already less than MEX, skip } else { // a[i] > mex: gap exists, MEX isn't present, wrap around mex = 0; ops++; // This pass ends with MEX=0 removal (empty round) } } return ops; } }
O(N log N)O(1)import java.util.*; public class GraphBeauty { static List<int[]>[] graph; // [neighbor, beauty] static int n; static boolean canReach(int src, int dst, int minBeauty) { boolean[] visited = new boolean[n+1]; Queue<Integer> q = new LinkedList<>(); q.offer(src); visited[src] = true; while (!q.isEmpty()) { int cur = q.poll(); if (cur == dst) return true; for (int[] e : graph[cur]) if (!visited[e[0]] && e[1] >= minBeauty) { visited[e[0]] = true; q.offer(e[0]); } } return false; } public static int maxBottleneck(int src, int dst, int[] beautyVals) { Arrays.sort(beautyVals); int lo = 0, hi = beautyVals.length - 1, ans = -1; while (lo <= hi) { int mid = (lo + hi) / 2; if (canReach(src, dst, beautyVals[mid])) { ans = beautyVals[mid]; lo = mid + 1; } else hi = mid - 1; } return ans; } }
O((V+E) log E)O(V+E)import java.util.*; public class CircularChairs { public static int[] minTimeToReach(int n, boolean[] occupied) { int[] dist = new int[n]; Arrays.fill(dist, Integer.MAX_VALUE); Queue<Integer> q = new LinkedList<>(); for (int i = 0; i < n; i++) if (occupied[i]) { dist[i] = 0; q.offer(i); } while (!q.isEmpty()) { int cur = q.poll(); int[] nexts = {(cur+1)%n, (cur-1+n)%n}; for (int nx : nexts) if (dist[nx] == Integer.MAX_VALUE) { dist[nx] = dist[cur] + 1; q.offer(nx); } } return dist; // dist[i] = min steps for any person to reach chair i } }
O(N)O(N)public class XORPartition { public static int minPartitions(int[] a, int target) { int xorSoFar = 0, parts = 0; int runTarget = target; for (int x : a) { xorSoFar ^= x; if (xorSoFar == runTarget) { // End of a valid partition parts++; xorSoFar = 0; // Reset for next segment } } // Valid if all elements are covered (xorSoFar == 0 at end) return (xorSoFar == 0) ? parts : -1; } // Note: Also check if total XOR == target β if yes, partition into single subarray }
O(N)O(1)import java.util.*; public class MinKLongestPath { static int n; static int[][] adjMatrix; // adjMatrix[u][v] = weight, -1 if no edge static int longestPathWithThreshold(int T) { int[] dp = new int[n]; int ans = 0; // Process nodes in topological order (assumed 0..n-1) for (int u = 0; u < n; u++) { for (int v = 0; v < n; v++) { if (adjMatrix[u][v] >= T) { dp[v] = Math.max(dp[v], dp[u] + 1); ans = Math.max(ans, dp[v]); } } } return ans; } public static int solve(int k, int[] weights) { int[] sorted = weights.clone(); Arrays.sort(sorted); int lo = 0, hi = sorted.length - 1, ans = 0; while (lo <= hi) { int mid = (lo + hi) / 2; if (longestPathWithThreshold(sorted[mid]) >= k) { ans = sorted[mid]; lo = mid + 1; } else hi = mid - 1; } return ans; } }
O(nΒ² log n)O(n)public class ArrayAPQueries { public static long[] solve(int n, int[][] queries) { long[] D1 = new long[n + 2]; long[] D2 = new long[n + 2]; for (int[] q : queries) { int l = q[0], r = q[1]; long a = q[2], d = q[3]; // AP: a, a+d, a+2d, ... int len = r - l + 1; D1[l] += a; D1[r+1] -= (a + (long)len * d); D2[l] += d; D2[r+1] -= d; } // Reconstruct: two prefix sum passes long[] res = new long[n]; long val = 0, inc = 0; for (int i = 0; i < n; i++) { inc += D2[i]; val += D1[i] + inc; res[i] = val; } return res; } }
O(Q)O(N)O(N)public class ThreeDXYZDP { public static long maxPathSum(int n, int[][][] grid) { long[][][] dp = new long[n][n][n]; for (int x = 0; x < n; x++) { for (int y = 0; y < n; y++) { for (int z = 0; z < n; z++) { long best = Long.MIN_VALUE; if (x==0 && y==0 && z==0) { dp[0][0][0] = grid[0][0][0]; continue; } if (x > 0) best = Math.max(best, dp[x-1][y][z]); if (y > 0) best = Math.max(best, dp[x][y-1][z]); if (z > 0) best = Math.max(best, dp[x][y][z-1]); dp[x][y][z] = best + grid[x][y][z]; } } } return dp[n-1][n-1][n-1]; } }
O(NΒ³)O(NΒ³)import java.util.*; public class TreeBeautifulSet { static List<Integer>[] tree; static int[] val; // node values static int ans = 0; static int dfs(int node, int par) { int maxFromChild = 0; for (int child : tree[node]) { if (child == par) continue; int childBest = dfs(child, node); // Update answer: path through this node using best two child subtrees ans = Math.max(ans, maxFromChild + childBest + 1); maxFromChild = Math.max(maxFromChild, childBest); } ans = Math.max(ans, maxFromChild + 1); return maxFromChild + 1; // Best chain including this node } public static int solve(int n, int[][] edges) { tree = new List[n + 1]; for (int i = 1; i <= n; i++) tree[i] = new ArrayList<>(); for (int[] e : edges) { tree[e[0]].add(e[1]); tree[e[1]].add(e[0]); } ans = 1; dfs(1, -1); return ans; } }
O(N)O(N)3 fresh questions in authentic HackWithInfy style. Set a 3-hour timer. Try each before expanding the solution.
public class StaircaseSteps { static final int MOD = 1_000_000_007; public static long countWays(int n) { if (n == 1) return 1; if (n == 2) return 2; // Space-optimized: only need last two values long prev2 = 1, prev1 = 2; for (int i = 3; i <= n; i++) { long curr = (prev1 + prev2) % MOD; prev2 = prev1; prev1 = curr; } return prev1; } public static void main(String[] args) { System.out.println(countWays(4)); // 5 System.out.println(countWays(10)); // 89 System.out.println(countWays(1000000)); // Very large, mod applied } }
O(N)O(1)import java.util.*; public class MinimumPlatforms { public static int findPlatforms(int[] arr, int[] dep) { Arrays.sort(arr); Arrays.sort(dep); int platforms = 1, maxPlatforms = 1; int i = 1, j = 0; // i = arrival pointer, j = departure pointer while (i < arr.length && j < dep.length) { if (arr[i] <= dep[j]) { // A train arrives before earliest departure β need new platform platforms++; i++; } else { // A train departs before next arrival β platform freed platforms--; j++; } maxPlatforms = Math.max(maxPlatforms, platforms); } return maxPlatforms; } public static void main(String[] args) { int[] arr = {900,940,950,1100,1500,1800}; int[] dep = {910,1200,1120,1130,1900,2000}; System.out.println(findPlatforms(arr, dep)); // 3 } }
O(N log N)O(1)import java.util.*; public class WordLadder { public static int ladderLength(String begin, String end, List<String> wordList) { Set<String> wordSet = new HashSet<>(wordList); if (!wordSet.contains(end)) return 0; Queue<String> q = new LinkedList<>(); q.offer(begin); int steps = 1; while (!q.isEmpty()) { int size = q.size(); while (size-- > 0) { String curr = q.poll(); char[] chars = curr.toCharArray(); for (int i = 0; i < chars.length; i++) { char orig = chars[i]; for (char c = 'a'; c <= 'z'; c++) { if (c == orig) continue; chars[i] = c; String next = new String(chars); if (next.equals(end)) return steps + 1; if (wordSet.remove(next)) q.offer(next); } chars[i] = orig; // Restore } } steps++; } return 0; } public static void main(String[] args) { System.out.println(ladderLength("hit", "cog", Arrays.asList("hot","dot","dog","lot","log","cog"))); // 5 } }
O(N Γ L Γ 26)O(N Γ L)Every topic has a concept explanation, a representative problem, and a complete Java solution. Study these in roadmap order.
| Algorithm | Time | Space | Use Case |
|---|---|---|---|
| Binary Search | O(log N) | O(1) | Sorted array queries |
| BFS/DFS | O(V+E) | O(V) | Graph traversal |
| Dijkstra | O((V+E) log V) | O(V) | Shortest path weighted |
| Merge Sort | O(N log N) | O(N) | Stable sort, inversions |
| Kadane's | O(N) | O(1) | Max subarray sum |
| Sliding Window | O(N) | O(1)-O(N) | Contiguous subarrays |
| Heap (PQ) | O(N log N) | O(N) | K-th smallest/largest |
| Union-Find | O(N Ξ±(N)) | O(N) | Connected components |
| Segment Tree | O(N) build, O(log N) query | O(N) | Range queries |
| Trie | O(L) per op | O(NΓL) | String prefix search |
| LCS/LIS | O(NΒ²) or O(N log N) | O(N) | Sequence DP |
| Tree DP | O(N) | O(N) | Tree path problems |
Prefix Sum: pre[i] = A[0] + A[1] + ... + A[i]. Range sum query [l,r] = pre[r] - pre[l-1] in O(1).
Difference Array: D[i] = A[i] - A[i-1]. Range update [l,r] by +k β D[l]+=k, D[r+1]-=k. Reconstruct with prefix sum. Turns O(n) per update into O(1) per update, O(n) final reconstruction.
Representative Problem: Given array A and Q range-add queries, find the final array.
public class DiffArray { public static int[] rangeUpdates(int n, int[][] updates) { int[] diff = new int[n + 1]; for (int[] u : updates) { // [l, r, val] diff[u[0]] += u[2]; if (u[1] + 1 <= n) diff[u[1] + 1] -= u[2]; } // Prefix sum to reconstruct final array for (int i = 1; i < n; i++) diff[i] += diff[i-1]; return diff; } }
O(1)O(N+Q)Maintain a window [left, right]. Expand right to include elements. Shrink from left when a constraint is violated. The window always represents a valid state. Used for: longest subarray with sum β€ K, max length with at most K distinct characters, minimum window substring.
Problem: Longest subarray with sum β€ K.
public class SlidingWindow { public static int longestSubarrayWithSumK(int[] a, int k) { int left = 0, sum = 0, maxLen = 0; for (int right = 0; right < a.length; right++) { sum += a[right]; while (sum > k && left <= right) sum -= a[left++]; maxLen = Math.max(maxLen, right - left + 1); } return maxLen; } }
O(N)O(1)"Binary Search on Answer" pattern: when the answer lies in a monotonic range and you can check feasibility in O(f(n)), binary search the answer. Common problems: "minimize maximum", "maximize minimum", "find smallest K such that condition holds".
Problem: Split N books of chapters into K groups. Minimize the maximum sum in any group (Painter's Partition).
public class PaintersPartition { static boolean feasible(int[] books, int k, long maxWork) { int painters = 1; long curr = 0; for (int b : books) { if (curr + b > maxWork) { painters++; curr = b; } else curr += b; } return painters <= k; } public static long minTime(int[] books, int k) { long lo = 0, hi = 0; for (int b : books) { lo = Math.max(lo, b); hi += b; } while (lo < hi) { long mid = (lo + hi) / 2; if (feasible(books, k, mid)) hi = mid; else lo = mid + 1; } return lo; } }
O(N log(sum))O(1)BFS (Queue): Explores level by level. Gives shortest path in unweighted graphs. Use when: minimum steps, nearest cell, flood fill.
DFS (Stack/Recursion): Goes deep before backtracking. Use when: cycle detection, connected components, topological sort, tree paths.
Multi-source BFS: Add all sources to queue at time=0. Automatically gives min distance from ANY source.
Problem: 0/1 Matrix β find distance of each cell from nearest 0.
import java.util.*; public class ZeroOneMatrix { public static int[][] updateMatrix(int[][] mat) { int R = mat.length, C = mat[0].length; int[][] dist = new int[R][C]; Queue<int[]> q = new LinkedList<>(); for (int i = 0; i < R; i++) for (int j = 0; j < C; j++) if (mat[i][j] == 0) q.offer(new int[]{i,j}); else dist[i][j] = Integer.MAX_VALUE; int[][] d = {{0,1},{0,-1},{1,0},{-1,0}}; while (!q.isEmpty()) { int[] cur = q.poll(); for (int[] dir : d) { int r=cur[0]+dir[0], c=cur[1]+dir[1]; if (r>=0&&r<R&&c>=0&&c<C && dist[r][c]>dist[cur[0]][cur[1]]+1) { dist[r][c] = dist[cur[0]][cur[1]] + 1; q.offer(new int[]{r,c}); } } } return dist; } }
O(RΓC)O(RΓC)A heap is a complete binary tree. Min-Heap: parent β€ children (Java PriorityQueue default). Max-Heap: parent β₯ children (use reverse comparator). Insert/Delete: O(log N). Peek (min/max): O(1). Key patterns: K largest elements (use min-heap of size K), K smallest (max-heap), merge K sorted lists, median of stream.
Problem: Find median from a data stream.
import java.util.*; public class MedianFinder { PriorityQueue<Integer> small = new PriorityQueue<>(Collections.reverseOrder()); // max-heap (lower half) PriorityQueue<Integer> large = new PriorityQueue<>(); // min-heap (upper half) public void addNum(int num) { small.offer(num); large.offer(small.poll()); // Balance: max of small goes to large if (small.size() < large.size()) small.offer(large.poll()); // Keep small size >= large size } public double findMedian() { if (small.size() > large.size()) return small.peek(); return (small.peek() + large.peek()) / 2.0; } }
O(log N)O(1)DP solves problems with overlapping subproblems and optimal substructure. Two approaches:
Top-down (Memoization): Recursion + cache results. Easier to write.
Bottom-up (Tabulation): Fill a table iteratively. Better for space optimization.
Classic problems: 0/1 Knapsack, LCS, LIS, Coin Change, Edit Distance, Partition DP.
Problem: Longest Increasing Subsequence (LIS) in O(N log N).
import java.util.*; public class LIS { public static int lengthOfLIS(int[] nums) { List<Integer> tails = new ArrayList<>(); for (int num : nums) { // Binary search: find first tail >= num int lo = 0, hi = tails.size(); while (lo < hi) { int mid = (lo + hi) / 2; if (tails.get(mid) < num) lo = mid + 1; else hi = mid; } if (lo == tails.size()) tails.add(num); else tails.set(lo, num); // Replace to keep tails as small as possible } return tails.size(); } }
O(N log N)O(N)DSU tracks which elements belong to the same set. Two operations: find(x) = root of x's set, union(x,y) = merge x and y's sets. Optimizations: Path Compression (flatten tree in find), Union by Rank (attach smaller tree under larger). With both: nearly O(1) per operation.
Problem: Number of connected components in an undirected graph.
public class DSU { int[] parent, rank; DSU(int n) { parent = new int[n]; rank = new int[n]; for (int i = 0; i < n; i++) parent[i] = i; } int find(int x) { if (parent[x] != x) parent[x] = find(parent[x]); // Path compression return parent[x]; } boolean union(int x, int y) { int rx = find(x), ry = find(y); if (rx == ry) return false; // Already same set if (rank[rx] < rank[ry]) { int t=rx; rx=ry; ry=t; } parent[ry] = rx; // Union by rank if (rank[rx] == rank[ry]) rank[rx]++; return true; } public static int countComponents(int n, int[][] edges) { DSU dsu = new DSU(n); int components = n; for (int[] e : edges) if (dsu.union(e[0], e[1])) components--; return components; } }
O(Ξ±(N)) per opO(N)Segment tree divides an array into segments. Each node stores aggregate (sum/min/max) of a range. Build: O(N). Query range [l,r]: O(log N). Update a point: O(log N). The tree is stored as an array: node i β children 2i and 2i+1. Leaf nodes are individual elements.
Problem: Range sum queries with point updates.
public class SegTree { int[] tree; int n; SegTree(int[] arr) { n = arr.length; tree = new int[4*n]; build(arr, 1, 0, n-1); } void build(int[] arr, int node, int s, int e) { if (s == e) { tree[node] = arr[s]; return; } int m = (s+e)/2; build(arr, 2*node, s, m); build(arr, 2*node+1, m+1, e); tree[node] = tree[2*node] + tree[2*node+1]; } void update(int node, int s, int e, int idx, int val) { if (s == e) { tree[node] = val; return; } int m = (s+e)/2; if (idx <= m) update(2*node, s, m, idx, val); else update(2*node+1, m+1, e, idx, val); tree[node] = tree[2*node] + tree[2*node+1]; } int query(int node, int s, int e, int l, int r) { if (r < s || e < l) return 0; // Out of range if (l <= s && e <= r) return tree[node]; // Fully covered int m = (s+e)/2; return query(2*node, s, m, l, r) + query(2*node+1, m+1, e, l, r); } }
O(N)O(log N)O(log N)Tree DP computes values bottom-up (leaves β root). Each node's answer depends on its children's computed values. Key patterns: maximum path sum in tree (diameter), max independent set on tree, counting paths with property. "Rerooting" technique: first DFS downward, then DFS upward to aggregate from parent's direction too.
Problem: Diameter of a tree (longest path between any two nodes).
import java.util.*; public class TreeDiameter { static List<Integer>[] adj; static int diameter = 0; static int dfs(int u, int par) { int maxDepth = 0, secondMax = 0; for (int v : adj[u]) { if (v == par) continue; int depth = dfs(v, u) + 1; if (depth >= maxDepth) { secondMax = maxDepth; maxDepth = depth; } else if (depth > secondMax) secondMax = depth; } // Path through node u: maxDepth + secondMax (or just maxDepth if leaf) diameter = Math.max(diameter, maxDepth + secondMax); return maxDepth; } }
O(N)O(N)Trie is a tree where each path from root to a node represents a string prefix. Each node has up to 26 children (for lowercase letters). Insert a word: O(L). Search a prefix: O(L). Used for: autocomplete, longest common prefix, word search, XOR maximization (binary trie).
public class Trie { private Trie[] children = new Trie[26]; private boolean isEnd; public void insert(String word) { Trie cur = this; for (char c : word.toCharArray()) { int idx = c - 'a'; if (cur.children[idx] == null) cur.children[idx] = new Trie(); cur = cur.children[idx]; } cur.isEnd = true; } public boolean startsWith(String prefix) { Trie cur = this; for (char c : prefix.toCharArray()) { int idx = c - 'a'; if (cur.children[idx] == null) return false; cur = cur.children[idx]; } return true; } }
O(L)O(L)O(NΓL)Kadane's finds maximum subarray sum in O(N). Key recurrence: cur = max(cur + a[i], a[i]). If cur goes negative, start fresh. Variants: maximum subarray product (track both max and min β negatives matter), maximum sum circular subarray (total sum β minimum subarray sum), max subarray with at most K elements.
public class Kadane { public static int maxSubarraySum(int[] a) { int maxSoFar = a[0], cur = a[0]; for (int i = 1; i < a.length; i++) { cur = Math.max(a[i], cur + a[i]); maxSoFar = Math.max(maxSoFar, cur); } return maxSoFar; } // Circular variant: max of (normal Kadane) vs (total β minSubarray) public static int maxCircularSubarray(int[] a) { int total = 0, maxSum = a[0], minSum = a[0], curMax = 0, curMin = 0; for (int x : a) { curMax = Math.max(curMax + x, x); maxSum = Math.max(maxSum, curMax); curMin = Math.min(curMin + x, x); minSum = Math.min(minSum, curMin); total += x; } return maxSum > 0 ? Math.max(maxSum, total - minSum) : maxSum; } }
O(N)O(1)Monotonic Stack maintains elements in increasing or decreasing order. When you push a new element, pop all elements it "dominates". Next Greater Element: maintain decreasing stack. Next Smaller: increasing stack. Applications: histogram max rectangle, daily temperatures, stock span, trapping rain water.
import java.util.*; public class LargestRectangle { public static int largestArea(int[] h) { Deque<Integer> stack = new ArrayDeque<>(); int maxArea = 0; for (int i = 0; i <= h.length; i++) { int currH = (i == h.length) ? 0 : h[i]; while (!stack.isEmpty() && h[stack.peek()] > currH) { int height = h[stack.pop()]; int width = stack.isEmpty() ? i : i - stack.peek() - 1; maxArea = Math.max(maxArea, height * width); } stack.push(i); } return maxArea; } }
O(N)O(N)Dijkstra finds shortest path from source to all nodes in a non-negative weighted graph. Uses a min-heap to always process the node with smallest known distance. dist[u] = min weight from source to u. Relaxation: if dist[u] + w(u,v) < dist[v], update dist[v].
import java.util.*; public class Dijkstra { public static long[] shortestPath(int n, List<int[]>[] graph, int src) { long[] dist = new long[n]; Arrays.fill(dist, Long.MAX_VALUE); dist[src] = 0; PriorityQueue<long[]> pq = new PriorityQueue<>((a,b) -> Long.compare(a[0],b[0])); pq.offer(new long[]{0, src}); while (!pq.isEmpty()) { long[] cur = pq.poll(); long d = cur[0]; int u = (int)cur[1]; if (d > dist[u]) continue; // Outdated entry for (int[] edge : graph[u]) { int v = edge[0]; long w = edge[1]; if (dist[u] + w < dist[v]) { dist[v] = dist[u] + w; pq.offer(new long[]{dist[v], v}); } } } return dist; } }
O((V+E) log V)O(V+E)Backtracking builds a solution incrementally. At each step, try all valid options. If stuck, undo the last choice (backtrack) and try another. Key template: choose β explore β unchoose. Pruning (early termination) makes it efficient. Common use: all subsets, permutations, N-Queens, Sudoku solver, word search in grid.
Problem: Generate all subsets (power set) of an array.
import java.util.*; public class Subsets { public static List<List<Integer>> subsets(int[] nums) { List<List<Integer>> result = new ArrayList<>(); backtrack(nums, 0, new ArrayList<>(), result); return result; } static void backtrack(int[] nums, int start, List<Integer> curr, List<List<Integer>> result) { result.add(new ArrayList<>(curr)); // Record current state for (int i = start; i < nums.length; i++) { curr.add(nums[i]); // Choose backtrack(nums, i + 1, curr, result); // Explore curr.remove(curr.size() - 1); // Unchoose (backtrack) } } }
O(2α΄Ί Γ N)O(N)50+ commonly asked theoretical questions in technical rounds. Know these concepts cold.
[] syntax; ArrayList is part of Collections framework with methods like add(), remove(), get()add(int, int), add(double, double), add(int, int, int)toString(), equals() overridden in custom classes
"hello" == "hello" β true (string pool)new String("hello") == "hello" β falseSystem.gc() (suggestion, not guarantee)
Master these smaller patterns first. Every HackWithInfy question is a combination of 2β3 of these building blocks.
Store each element in a map. For each element x, check if (target β x) exists. O(N) time. Foundation for 3-sum, 4-sum, pair-with-given-sum problems.
Count occurrences using HashMap or int[]. Used in: anagram check, majority element, first non-repeating character, character frequency in strings.
Use stack for balanced parentheses, expression evaluation, undo operations. Push on open, pop on close. Valid brackets check is a 5-line solution.
Precompute prefix sums. Answer range sum in O(1). Essential for all range query problems. pre[r+1] - pre[l] = sum of A[l..r].
Rotate array by k positions: reverse whole β reverse first k β reverse remaining. O(N) time, O(1) space. Cleaner than shift-and-copy.
Compute a^n mod p in O(log N). Essential for modular arithmetic. Uses the identity: a^n = (a^(n/2))Β² if n even, a Γ a^(n-1) if n odd.
Sort intervals by start time. Merge overlapping ones: if cur.start β€ prev.end, merge by extending end. O(N log N). Used in calendar, task scheduling, meeting rooms problems.
Find K largest: use min-heap of size K. For K smallest: use max-heap of size K. Each insertion: if heap size > K, remove worst. O(N log K).
When states form a graph not explicitly given. Model states as nodes, transitions as edges. BFS gives min steps. Used in: word ladder, sliding puzzle, knight on chessboard.
dp[i][j] = answer for cell (i,j). Fill row by row. Transition from top and left. Used in: unique paths, minimum path sum, dungeon game, edit distance table.
Process nodes in dependency order. Compute in-degrees. Add 0-in-degree nodes to queue. Process and reduce neighbors' in-degrees. Used in: task order, course schedule, build systems.
Compute polynomial hash of string. Rolling hash allows O(1) substring hash computation after O(N) build. Used in: Rabin-Karp string matching, finding duplicate substrings.
Precompute answers for ranges of power-of-2 lengths. Build: O(N log N). Query: O(1). Used for LCA in trees and static RMQ problems where no updates occur.
When state space is small (β€ 20 elements), represent subsets as bitmasks. dp[mask] = best answer using the subset represented by mask. Used in: TSP, minimum XOR, shortest superstring.
Express a linear recurrence as matrix multiplication. Compute A^n in O(kΒ³ log n) where k = state size. Used in: Fibonacci in O(log N), linear recurrences with large n (up to 10ΒΉβΈ).
Gaussian elimination over GF(2). Maintain a basis of XOR-independent vectors. Find max XOR of any subset. Used in: maximum XOR subarray, XOR basis queries.
Precompute ancestors at power-of-2 distances. LCA query: lift both nodes to same depth, then binary lift together. Build: O(N log N). Query: O(log N). Essential for tree path problems.
Process range queries offline sorted by block. Maintain a window, extending/shrinking by 1. Total operations: O((N+Q)βN). Best for static arrays with complex aggregates where sliding window is O(1).
A structured path from beginner to solving all 3 questions in a HackWithInfy exam. Follow this order β do not skip ahead.
Master the most common patterns. These patterns appear in almost every Easy question and as sub-parts of Medium questions. Focus on clean, bug-free code, not speed.
Binary Search (standard + on answer) and Greedy with Priority Queue. These unlock a large portion of Medium questions and are frequently tested.
BFS/DFS are the single most tested category. Multi-source BFS, BFS on implicit graphs, DFS with state, topological sort. At least one question involves a grid or graph.
The hardest and most varied topic. Start with 1D DP, move to 2D, then special forms. DP is always in the Hard question.
Trees are tested every year. Master DFS on trees, Tree DP (diameter, path problems), LCA. These problems are medium-hard level and combine tree structure with DP.
Segment Tree, Trie, Monotonic Stack, XOR operations. Then: 3 full mock exams (3 hours each). Review every solution after each mock. Focus on edge cases and overflow.
30 min Easy, 60 min Medium, 90 min Hard. First 5 minutes: read ALL 3 problems. Start with the easiest, but don't ignore the others. Partial solutions get partial credit. Always write brute force first, then optimize. Annotate your code β readability matters.