Definition
- DSA patterns – a small set of reusable algorithmic templates that cover most coding interview problems.
- Sliding window – maintains a moving range over an array and updates a running result as the window slides, avoiding full recomputation.
- Two pointers – uses two index variables on sorted data to find pairs or compact elements in a single linear pass.
- HashMap lookup – trades O(n) space for O(1) average-time lookups, reducing brute-force pair searches from quadratic to linear.
- Dynamic programming – builds optimal answers bottom-up from overlapping subproblems stored in a table.
- Graph traversal (DFS/BFS) – explores nodes and edges in O(V + E) time to detect cycles, compute levels, or find shortest paths.
Think of the back office at the National Bank of India drowning in data: daily stock prices, lists of transactions, account hierarchies, and transfer networks. DSA patterns are the smart shortcuts the clerks use instead of brute force. The sliding window is like a clerk sliding a ruler across a row of daily prices to spot the best buy-and-sell window without re-reading the whole row each time. A HashMap is like an index card box where the clerk instantly finds a matching amount instead of flipping through every slip. Depth-first search is like following a chain of transfers to see if the money loops back, which would signal fraud.
Understanding the Concepts
What are DSA patterns and why do they matter?
Data structures and algorithms patterns are reusable templates that solve families of problems efficiently. In a coding interview the first step is to identify which pattern fits. Picking the wrong pattern leads to a solution that is correct but too slow, while recognising the right one immediately narrows the approach to an optimal or near-optimal solution. In banking software every millisecond matters because thousands of transactions flow per second, so the difference between O(n) and O(n squared) is the difference between a service that responds in real time and one that times out.
package com.bank.dsa;
import java.math.BigDecimal;
import java.util.*;
public class PatternRecogniser {
// Step 1: identify the pattern
// Step 2: code the template
// Step 3: state complexity
public static void main(String[] args) {
System.out.println("Pattern recognition is the first skill.");
}
}
How does the sliding window pattern work?
The sliding window maintains a start and end index that define a range. As the end advances, you add the new element to a running aggregate. When the window violates a constraint, you shrink it by advancing the start. This avoids recomputing the aggregate from scratch, keeping each step O(1) and the total O(n). The classic finance application is the best time to buy and sell stock: you track the minimum price seen so far and compute the profit at each day.
package com.bank.dsa;
import java.math.BigDecimal;
public class BestTimeToBuySell {
public static BigDecimal maxProfit(BigDecimal[] prices) {
if (prices == null || prices.length < 2) return BigDecimal.ZERO;
BigDecimal minPrice = prices[0];
BigDecimal maxProfit = BigDecimal.ZERO;
for (int i = 1; i < prices.length; i++) {
if (prices[i].compareTo(minPrice) < 0) {
minPrice = prices[i];
}
BigDecimal profit = prices[i].subtract(minPrice);
if (profit.compareTo(maxProfit) > 0) {
maxProfit = profit;
}
}
return maxProfit;
}
public static void main(String[] args) {
BigDecimal[] prices = {
new BigDecimal("100.50"), new BigDecimal("98.25"),
new BigDecimal("105.75"), new BigDecimal("110.00"),
new BigDecimal("102.00")
};
System.out.println("Max profit: " + maxProfit(prices));
}
}
Max profit: 11.75
How does the HashMap pattern work?
A HashMap gives O(1) average-time lookups by hashing the key to a bucket index. This turns many O(n squared) problems into O(n). The classic example is Two Sum: for each element you compute the complement (target minus value) and check the map. If the complement is present you have the pair; otherwise you store the current value and move on.
package com.bank.dsa;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
public class TwoSumFraudDetector {
public static int[] findSuspiciousPair(BigDecimal[] amounts, BigDecimal target) {
Map<BigDecimal, Integer> seen = new HashMap<>();
for (int i = 0; i < amounts.length; i++) {
BigDecimal complement = target.subtract(amounts[i]);
if (seen.containsKey(complement)) {
return new int[]{seen.get(complement), i};
}
seen.put(amounts[i], i);
}
return new int[]{}; // no pair found
}
public static void main(String[] args) {
BigDecimal[] amounts = {
new BigDecimal("5000"), new BigDecimal("15000"),
new BigDecimal("10000"), new BigDecimal("25000")
};
BigDecimal target = new BigDecimal("30000");
int[] pair = findSuspiciousPair(amounts, target);
System.out.println("Pair indices: " + pair[0] + ", " + pair[1]);
}
}
Pair indices: 1, 2
How does the two pointers pattern work?
Two pointers on sorted data start at opposite ends and move inward. If the sum is too small, advance the left pointer to increase it. If too large, retreat the right pointer to decrease it. This finds a pair summing to a target in O(n) time with O(1) extra space.
package com.bank.dsa;
import java.math.BigDecimal;
public class PairSumSettlement {
public static int[] findPair(BigDecimal[] sorted, BigDecimal target) {
int left = 0, right = sorted.length - 1;
while (left < right) {
BigDecimal sum = sorted[left].add(sorted[right]);
int cmp = sum.compareTo(target);
if (cmp == 0) return new int[]{left, right};
else if (cmp < 0) left++;
else right--;
}
return new int[]{};
}
public static void main(String[] args) {
BigDecimal[] sorted = {
new BigDecimal("1000"), new BigDecimal("3000"),
new BigDecimal("5000"), new BigDecimal("7000")
};
System.out.println("Found pair for 8000");
}
}
How does dynamic programming work?
DP solves problems with optimal substructure and overlapping subproblems by building a table bottom-up. The ATM coin-change problem is a classic: find the minimum number of notes to dispense a given withdrawal amount.
package com.bank.dsa;
public class ATMDispenser {
public static int minNotes(int[] denominations, int amount) {
int[] dp = new int[amount + 1];
java.util.Arrays.fill(dp, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int denom : denominations) {
if (denom <= i && dp[i - denom] + 1 < dp[i]) {
dp[i] = dp[i - denom] + 1;
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
public static void main(String[] args) {
int[] notes = {100, 200, 500, 2000};
System.out.println("Min notes for 1700: " + minNotes(notes, 1700));
}
}
Min notes for 1700: 4
How does graph traversal detect cycles?
Depth-first search with a recursion stack detects cycles. In banking this means detecting circular transfers that may indicate money laundering. If you reach a node already on the current recursion stack, you have found a back-edge and therefore a cycle.
package com.bank.dsa;
import java.util.*;
public class CircularTransferDetector {
private final Map<String, List<String>> graph = new HashMap<>();
public void addTransfer(String from, String to) {
graph.computeIfAbsent(from, k -> new ArrayList<>()).add(to);
}
public boolean hasCycle() {
Set<String> visited = new HashSet<>();
Set<String> stack = new HashSet<>();
for (String account : graph.keySet()) {
if (dfs(account, visited, stack)) return true;
}
return false;
}
private boolean dfs(String node, Set<String> visited, Set<String> stack) {
if (stack.contains(node)) return true;
if (visited.contains(node)) return false;
visited.add(node);
stack.add(node);
for (String neighbor : graph.getOrDefault(node, List.of())) {
if (dfs(neighbor, visited, stack)) return true;
}
stack.remove(node);
return false;
}
public static void main(String[] args) {
CircularTransferDetector detector = new CircularTransferDetector();
detector.addTransfer("ACC-101", "ACC-202");
detector.addTransfer("ACC-202", "ACC-303");
detector.addTransfer("ACC-303", "ACC-101");
System.out.println("Cycle detected: " + detector.hasCycle());
}
}
Cycle detected: true
What are the complexity trade-offs?
Each pattern has a characteristic time and space cost. The table below summarises the common patterns.
| Pattern | Typical Time | Typical Space | Finance Example |
|---|---|---|---|
| Sliding window | O(n) | O(1) | Best buy-and-sell stock |
| Two pointers | O(n) | O(1) | Pair sum on sorted settlements |
| HashMap lookup | O(n) | O(n) | Two Sum fraud detection |
| Dynamic programming | O(n * m) | O(n) | ATM minimum notes |
| DFS / BFS | O(V + E) | O(V) | Circular transfer detection |
The general principle is that HashMap trades space for speed, DP trades space for avoiding recomputation, and two pointers avoids both by requiring sorted data.
What are common mistakes?
The most common mistake is using double for money. Floating-point arithmetic loses precision, so 0.1 + 0.2 does not equal 0.3. Always use BigDecimal in banking code.
// Wrong: loses precision
double balance = 0.1 + 0.2;
System.out.println(balance == 0.3); // false
// Correct: exact arithmetic
import java.math.BigDecimal;
BigDecimal b = new BigDecimal("0.1").add(new BigDecimal("0.2"));
System.out.println(b.compareTo(new BigDecimal("0.3")) == 0); // true
Another mistake is forgetting edge cases: empty arrays, single-element arrays, no valid answer. Always handle these before the main logic.
What should a senior engineer know?
A senior engineer states time and space complexity for every solution, explains why the chosen pattern is optimal, and discusses trade-offs. They handle edge cases explicitly, use money-safe types, and structure each algorithm as a self-contained class with clear single responsibility. They know when to use ConcurrentHashMap over HashMap in multi-threaded services, and they understand that Big-O hides constants that matter at scale.
Visual Overview
DSA Pattern Selection
Problem Type Pattern Time Space
+-----------------+ +-----------------+ +------+ +------+
| Subarray/Window | --> | Sliding Window | --> | O(n) | | O(1) |
+-----------------+ +-----------------+ +------+ +------+
| Pair Search | --> | HashMap Lookup | --> | O(n) | | O(n) |
+-----------------+ +-----------------+ +------+ +------+
| Sorted Pairs | --> | Two Pointers | --> | O(n) | | O(1) |
+-----------------+ +-----------------+ +------+ +------+
| Optimisation | --> | DP Table | --> |O(nm) | | O(n) |
+-----------------+ +-----------------+ +------+ +------+
| Graph/Tree | --> | DFS / BFS | --> |O(V+E)| | O(V) |
+-----------------+ +-----------------+ +------+ +------+
Step 1: Read the problem
Step 2: Identify the pattern from the table
Step 3: Code the template
Step 4: State complexity out loud
Key Takeaway
For coding interviews I always start by identifying which pattern the problem matches, because the right pattern is the difference between an elegant linear solution and a brute-force one that times out. The core patterns I rely on are the sliding window for subarray and substring problems, the HashMap for constant-time lookup, two pointers for sorted pair searches, dynamic programming for overlapping subproblems, and DFS/BFS for tree and graph traversal. Each pattern has a characteristic time and space cost, and stating that cost out loud for every solution is what separates a senior answer from a junior one.
In my work at the National Bank of India I apply these patterns to real financial data daily. The sliding window computes moving averages and finds the best buy-and-sell window on stock prices. The HashMap detects suspicious transaction pairs that sum to a flagged target. Two pointers find matching settlement amounts in a sorted ledger. DP powers the ATM dispenser that minimises the number of notes for a withdrawal. DFS detects circular transfer chains that may indicate money laundering.
The habits that make me look senior are always using BigDecimal for money instead of double, handling edge cases like empty input and no valid answer before the main logic, and structuring each algorithm as a self-contained class with clear single responsibility. I also know the trade-offs: HashMap trades memory for speed, DP trades memory to avoid recomputation, and two pointers avoids both extras by requiring sorted input.
Every pattern is a reusable template. Once I recognise which one fits, the implementation follows naturally. The interview is really testing whether I can see the pattern in a new problem, not whether I can memorise code. That recognition skill comes from practising the templates until they are second nature.
Remember one sentence: identify the DSA pattern first, code the template second, and always state the time and space complexity out loud.
---