A campus hire heading into her NTT Data interview loop last year described the first hurdle as a 90-minute computer-based test covering aptitude, verbal reasoning, and a chunk of core computer engineering, C programming, operating systems, networking, SQL, before anyone even looked at her resume. Only around 155 of the roughly 700 candidates who sat that test moved forward. That funnel shape shows up across candidate reports again and again: NTT Data, the Japan-headquartered IT services and consulting arm of NTT Group, runs a written test, then a group discussion, then multiple technical rounds, before HR ever asks "tell me about yourself" (GeeksforGeeks interview experiences).
What candidates report is less "solve a hard LeetCode problem" and more "prove you actually understand the fundamentals you claim on your resume." The group discussion round is unusual for a tech employer, a 30-minute session with roughly a dozen candidates split into for/against positions on a business or policy topic, before the conversation ever turns technical. Once it does, expect OS scheduling and semaphores, networking subnetting problems, SQL joins, and straightforward OOP and coding questions rather than exotic algorithm puzzles. Experienced hires skip the group discussion and written test in most reports, going straight into a technical screen built around their resume and project history.
This page covers roughly 50 questions organized the way NTT Data's own rounds are organized: aptitude and MCQ-style screening, coding and data structures, core CS fundamentals (OS, networking, DBMS), Java and web development topics, SQL, architecture and project-discussion questions for experienced candidates, consulting and client-facing behavioral scenarios, and the closing HR round. Difficulty is a mix, weighted toward the medium fundamentals questions candidates actually report getting stuck on.
Written test and aptitude screening
This round filters volume before anyone talks to a human. Candidates describe a mix of quantitative aptitude, verbal and logical reasoning, and a technical section pulled from core CS coursework.
Easy questions
16Total distance covered is the train's length plus the platform's length, 150 plus 250 equals 400 meters, covered in 20 seconds. That gives a speed of 20 meters per second, which converts to 72 km/h by multiplying by 18/5.
These questions rarely trip up candidates on the math itself, the trap is misreading which distances to add. Anyone who's rusty on speed, time, and distance problems should spend an evening on them specifically rather than general aptitude prep, because the format repeats across almost every campus-hiring written test in this space, not just NTT Data's.
This is a syllogism-style question, and the only reliable method is Venn diagrams, not intuition. Draw the statement's relationship first, then test whether each conclusion holds in every possible diagram consistent with that statement, not just the most obvious one.
The most common mistake is accepting a conclusion because it sounds true in the real world. Logical reasoning sections test whether a conclusion is forced by the given statement alone, and plenty of real-world-true conclusions don't actually follow from the specific wording given.
Call by value copies the argument into the function's local parameter, so changes inside the function never touch the caller's original variable. Call by reference passes the address (or, in C++, a reference) so the function operates on the original memory location directly, and changes persist after the function returns.
void byValue(int x) { x = 100; } // caller's variable unchanged
void byRef(int *x) { *x = 100; } // caller's variable changed
int a = 5;
byValue(a); // a is still 5
byRef(&a); // a is now 100The brute-force nested loop works and is a fine place to start out loud, but the expected answer is a single pass with a hash set. Walk the array once, and for each number check whether target minus that number already exists in the set. If it does, you have your pair. If not, add the current number to the set and keep going.
def two_sum(nums, target):
seen = {}
for i, n in enumerate(nums):
complement = target - n
if complement in seen:
return [seen[complement], i]
seen[n] = i
return []This runs in O(n) time and O(n) space, versus O(n squared) for the brute force. Interviewers usually ask you to state the complexity out loud, not just produce working code.
An array stores elements in contiguous memory, which gives O(1) random access by index but makes insertion or deletion in the middle expensive, everything after the insertion point has to shift. A linked list stores elements as separate nodes connected by pointers, so insertion and deletion at a known position is O(1), but reaching an arbitrary index requires walking the list from the head, O(n).
Pick an array when you read far more than you insert or delete, and you know the size roughly in advance. Pick a linked list when insertions and deletions in the middle happen constantly and random access isn't a core requirement, a queue-like structure or an undo history are common real examples.
A semaphore is a counter that controls access to a resource with a limited number of instances, threads increment or decrement it, and block when it hits zero. A mutex is a special case, a binary lock owned by exactly one thread at a time, with the explicit rule that only the thread holding it can release it.
A counting semaphore can be released by a different thread than the one that acquired it, which is exactly the property that makes it fit for producer-consumer style coordination between separate threads. A mutex enforces ownership specifically to prevent that, which is why it's the right tool for protecting a single shared critical section rather than coordinating a pool of resources.
Physical (cables, radio signals), Data Link (Ethernet, MAC addressing), Network (IP, routing), Transport (TCP, UDP), Session (managing connections across a conversation), Presentation (encryption, encoding like TLS), Application (HTTP, DNS, FTP).
Most candidates can recite the layer names from bottom to top but stumble when asked to place a specific protocol correctly, especially confusing where TLS sits (Presentation, handling encryption) versus TCP (Transport, handling reliable delivery). Knowing that distinction cold is what separates memorized trivia from real understanding here.
Overloading means multiple methods share a name but differ in parameter list, resolved at compile time based on the arguments passed. Overriding means a subclass redefines a method it inherited from a parent class with the exact same signature, resolved at runtime based on the actual object type, not the reference type it's stored in.
class Calc {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; } // overload
}
class Animal { void sound() { System.out.println("..."); } }
class Dog extends Animal { void sound() { System.out.println("Bark"); } } // overridefinal is a keyword applied to a variable (making it a constant reference), a method (preventing overrides), or a class (preventing subclassing). finally is a block that always executes after a try/catch, whether or not an exception was thrown, typically used for cleanup like closing a file handle. finalize was a method the garbage collector called before reclaiming an object, letting it do last-minute cleanup, but it's deprecated as of Java 9 and removed in later versions because its timing was never reliable.
=== compares both value and type without converting either operand. == performs type coercion first, converting one or both operands to a common type before comparing, which produces results that surprise people who haven't memorized the coercion rules.
0 == "0" // true, string coerced to number
0 == "" // true, empty string coerced to 0
"0" == false // true, both coerced to 0
1 === "1" // false, no coercion, different typesThe practical advice, and what most interviewers want to hear, is to default to === everywhere and only reach for == in the rare case you deliberately want the coercion, because the coercion rules themselves are inconsistent enough that memorizing every edge case isn't worth it.
INNER JOIN returns only rows where the join condition matches in both tables. LEFT JOIN returns every row from the left table, with NULLs filled in for any columns from the right table where no match exists. RIGHT JOIN does the mirror image, keeping every row from the right table. FULL OUTER JOIN keeps every row from both tables, filling NULLs on whichever side didn't match.
SELECT o.order_id, c.name
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.id;
-- every order appears, even ones with a missing or deleted customer recordA primary key uniquely identifies each row in its own table and can't be null. A foreign key is a column (or set of columns) in one table that references a primary key in another table, enforcing that the referenced value actually exists.
A table has exactly one primary key, though that key can be composite, made up of more than one column. A table can have any number of foreign keys, each pointing at a different table or even the same table more than once, a common pattern for self-referencing hierarchies like an employee table with a manager_id pointing back to another row in the same table.
Say something specific and verifiable, not a paraphrase of the careers page. NTT Data is the IT services and consulting subsidiary of Japan's NTT Group, operating across systems integration, application development, and managed services for enterprise clients globally. Naming that parent-company context, plus one specific practice area, cloud, data, industry-specific consulting, that maps to the role you're interviewing for, shows you did more than skim a job posting.
Avoid answers that would apply equally to any large IT consultancy. The interviewer has heard "I want to work somewhere I can grow" enough times that it registers as filler rather than an actual answer.
Anchor the answer in one specific, verifiable thing from your background that maps directly to what the role needs, not a list of adjectives. "I've shipped three production features under a similar tech stack in the last year" beats "I'm a fast learner and a team player" because it's checkable and specific.
If you genuinely don't have a standout differentiator, name the closest real thing honestly rather than inventing one. Interviewers notice when an answer to this question doesn't hold up to a single follow-up question.
The honest, useful version of this answer connects a plausible next step to the actual role you're interviewing for, not a vague ambition disconnected from the job. If you're interviewing for a developer role, naming a path toward technical leadership or deeper specialization in a specific domain reads as more credible than a generic "management" answer that doesn't reference the actual work.
It's fine to admit some uncertainty about the exact title or level. What matters more is showing you've thought about growth in a direction the company can actually support, rather than treating the question as a formality to get through.
Structure this as a short, chronological arc, where you started, the through-line connecting your roles or projects, and why that arc leads naturally to this specific job. Avoid reciting your resume line by line, the interviewer already has it in front of them, and a verbal repeat of it wastes the one open-ended minute you get to frame your own narrative.
End on why this role specifically, not just "and now I'm looking for my next opportunity." That last sentence is what turns a summary into an actual answer to the question being asked.
Medium questions
25A break inside a switch statement only exits that switch, it does not exit an enclosing loop. Candidates who assume break always exits the nearest loop get this one wrong when a switch sits inside a for or while loop, because the switch's break just falls through to the code after the switch, and the loop keeps iterating.
for (int i = 0; i < 3; i++) {
switch (i) {
case 1:
break; // only breaks the switch, loop continues
}
printf("%d ", i);
}
// prints: 0 1 2Pointer arithmetic scales by the size of the type the pointer points to, not by raw bytes. Incrementing an int pointer moves it forward by 4 bytes (on most modern platforms), not 1, because the compiler knows it needs to skip a full int's worth of memory to reach the next element.
int arr[] = {10, 20, 30};
int *p = arr;
p++;
printf("%d", *p); // prints 20, not garbage from byte offset 1Iteratively, you walk the list once, keeping three pointers, previous, current, and next, and flip each node's next pointer to point backward instead of forward.
def reverse_list(head):
prev = None
while head:
nxt = head.next
head.next = prev
prev = head
head = nxt
return prevThe recursive version is shorter to write but easy to get backward on the first try. Reverse everything after the current node first, then fix the current node's own pointers.
def reverse_recursive(head):
if not head or not head.next:
return head
new_head = reverse_recursive(head.next)
head.next.next = head
head.next = None
return new_headMerge sort splits the array in half recursively until each piece has one element, then merges pairs back together in sorted order. The split step is always exactly log n levels deep regardless of the input's initial order, and merging at each level costs O(n) total, giving O(n log n) no matter what.
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
result, i, j = [], 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i]); i += 1
else:
result.append(right[j]); j += 1
return result + left[i:] + right[j:]Quicksort's worst case degrades to O(n squared) when the pivot choice is consistently bad, an already-sorted array with a naive first-element pivot, for instance, because the partitions become as unbalanced as possible every single time.
Floyd's cycle detection, the tortoise and hare, is the O(1)-space answer. Move one pointer one step at a time and a second pointer two steps at a time. If there's a cycle, the fast pointer eventually laps the slow one and they meet inside the loop. If there's no cycle, the fast pointer hits the end of the list first.
def has_cycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast:
return True
return FalseA doubly linked list gives you something a singly linked list doesn't: a pointer that already walks backward. Set one pointer at the head and one at the tail, and walk them toward each other, comparing values at each step, until they meet or cross.
def is_palindrome(head):
left, right = head, head
while right.next:
right = right.next
while left != right and left.prev != right:
if left.val != right.val:
return False
left = left.next
right = right.prev
return TrueThe banker's algorithm avoids deadlock by only granting a resource request if the resulting system state is still "safe", meaning there's some order in which every process could still finish given the resources currently available and each process's maximum stated need. It refuses a request that would leave the system in a state where no completion order exists, even if that request could technically be satisfied right now.
The catch candidates often miss: it requires knowing each process's maximum resource claim in advance, which real operating systems mostly don't have. It's a clean theoretical model asked to test whether you understand deadlock avoidance versus deadlock detection, not something you'll implement verbatim in production.
Round robin gives every process a fixed time slice in rotation, which is fair and avoids starvation but can hurt short jobs stuck waiting behind long ones within their queue position. Shortest job first minimizes average waiting time in theory, but a steady stream of short jobs can starve a long job indefinitely, since it never becomes the shortest one in the queue. Priority scheduling runs whatever has the highest priority next, which starves low-priority processes the same way unless the system uses aging, gradually increasing a waiting process's priority the longer it sits unscheduled.
A good answer names the fix, not just the problem. Aging is the standard mitigation for both SJF-style and priority starvation, and it's worth mentioning unprompted.
The network address comes from a bitwise AND of the IP address and the subnet mask. The number of usable hosts is 2 to the power of the number of host bits, minus 2, one address reserved for the network itself and one for the broadcast address.
IP: 192.168.1.130 Subnet mask: 255.255.255.192 (/26)
Host bits: 6 (32 - 26)
Usable hosts: 2^6 - 2 = 62
Network address: 192.168.1.128
Broadcast address: 192.168.1.191The most common mistake is forgetting to subtract 2 at the end, or miscounting host bits when the mask isn't a clean multiple of 8.
Reach for an abstract class when subclasses genuinely share state, constructor logic, or non-public helper methods, things an interface still can't provide. Reach for an interface when you're defining a contract that unrelated classes need to implement, especially since a class can implement multiple interfaces but extend only one class.
Default methods narrowed the gap, but they didn't erase it. An interface still can't hold instance fields to track state across method calls, and it can't have a constructor. If your "shared behavior" needs either of those, that's your signal it belongs in an abstract class, not an interface with default methods bolted on.
== compares object references, whether two variables point to the exact same object in memory..equals() compares actual content, whether two String objects hold the same sequence of characters, even if they're different objects.
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false, different objects
System.out.println(a.equals(b)); // true, same content
String c = "hello";
String d = "hello";
System.out.println(c == d); // true, both pulled from the string poolThat last case is the one that trips people up. String literals get interned in a shared pool, so two literals with the same text can point to the same object, while explicitly constructed String objects never do. The rule is: never rely on == for string comparison, period, regardless of which case you think you're in.
A closure is a function that remembers the variables from the scope it was created in, even after that outer scope has finished executing. This is what lets you build private state without a class.
function makeCounter() {
let count = 0;
return function () {
count += 1;
return count;
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2, count persisted between callscount isn't reset between calls because the returned inner function keeps a live reference to the exact variable it was defined alongside, not a copy of its value at creation time.
Middleware is a function that sits between an incoming request and the final route handler, with access to the request, the response, and a next function that passes control forward. Each middleware can inspect or modify the request, short-circuit the response entirely, like an auth check that rejects an unauthenticated request, or call next to hand off to whatever's registered after it.
function requireAuth(req, res, next) {
if (!req.headers.authorization) {
return res.status(401).send("Unauthorized");
}
next(); // pass control to the next middleware or route handler
}
app.get("/profile", requireAuth, (req, res) => res.send(req.user));The cleanest version avoids the common LIMIT/OFFSET-only approach, which breaks silently when there are duplicate salary values at the top.
SELECT MAX(salary) AS second_highest
FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);This handles duplicates correctly because it filters strictly by value, not by row position. A LIMIT 1 OFFSET 1 approach after ORDER BY salary DESC would return the same value twice if the top salary is tied, instead of the true second-highest distinct value.
First normal form requires every column to hold a single atomic value, no comma-separated lists stuffed into one cell. Second normal form requires every non-key column to depend on the entire primary key, not just part of it, which only matters once you have a composite key. Third normal form requires every non-key column to depend only on the primary key, not on another non-key column, removing what's called a transitive dependency.
A concrete third normal form violation: a table with employee_id, department_id, and department_name together. department_name depends on department_id, not directly on employee_id, so it belongs in a separate departments table. Leaving it in place means updating a department's name requires touching every employee row in that department instead of one row.
Atomicity means a transaction either completes fully or not at all, no partial writes left behind. Consistency means a transaction moves the database from one valid state to another, respecting every constraint. Isolation means concurrent transactions don't see each other's uncommitted intermediate state. Durability means once a transaction commits, it survives a crash, power loss, or restart immediately after.
A durability failure scenario: a payment system confirms "your order is placed" to the customer, then the server crashes before that commit is actually flushed to disk, and the order silently vanishes on restart. The customer was told it succeeded and it didn't. That's specifically a durability problem, not an atomicity or consistency one, because the transaction did commit from the application's point of view before the data was lost.
An index, typically a B-tree, maintains a sorted structure pointing at the rows containing each value, so a lookup that would otherwise scan every row can instead navigate the tree in roughly logarithmic time. Without an index, a query on an unindexed column forces a full table scan, checking every single row.
The cost shows up on writes, not reads. Every insert, update, or delete has to update every index on that table too, so a table with a dozen indexes writes noticeably slower than one with two. The practical answer interviewers want: index columns you filter or join on frequently, and be deliberate about not over-indexing a write-heavy table.
Vertical scaling means giving a single machine more CPU, memory, or disk. It's simple, requires no application changes, but hits a hard ceiling and a single point of failure. Horizontal scaling means adding more machines and distributing load across them, which scales further but only stays simple as long as the application is stateless.
It stops being straightforward the moment state enters the picture, session data tied to one server, a database that hasn't been sharded, or any in-memory cache that isn't shared across instances. At that point horizontal scaling requires real architectural work: externalizing session state, adding a load balancer with sticky sessions or none at all, and deciding how the data layer itself scales, which is usually the harder half of the problem.
Prioritize by risk, not coverage percentage. Write unit tests for the logic most likely to have edge cases, boundary conditions, error paths, unusual input, then a smaller number of integration tests covering the paths a real user would actually take through the feature. Full end-to-end coverage of every permutation is rarely realistic under a deadline, and chasing it usually means the highest-risk paths get the same attention as trivial ones.
What interviewers are actually listening for is whether you can explain your prioritization out loud, not whether you name every testing framework you know. A candidate who says "I'd test the payment calculation exhaustively and the button color once" understands risk. A candidate who lists testing pyramids without picking what matters for this specific feature doesn't.
The strongest version of this answer separates what the client explicitly requested from the underlying problem you diagnosed, and shows you raised it directly instead of quietly working around it. Name the moment you noticed the gap, how you framed the recommendation so it didn't sound like scope creep or a sales pitch, and what the client actually decided, including if they said no.
A weak answer here just describes doing good technical work. A strong one describes the conversation, how you convinced someone who didn't ask for more that more was worth their time and budget.
This is usually a delivery-risk or bad-news scenario: a deadline slipping, a scope change, a bug found late. What matters is whether you brought the bad news early and with a plan attached, rather than waiting until it was unavoidable or showing up with only the problem and no proposed path forward.
Mention the specific tradeoff you presented, not just that you "communicated proactively." A client remembers being given options more than they remember being told something was wrong.
The trap here is describing something merely competent as a breakthrough. Pick something that genuinely went against the initial group consensus, and explain specifically why the room didn't see it initially, a technical assumption everyone else had accepted, a constraint you questioned that others treated as fixed.
Close with what changed after you raised it, whether the team adopted it immediately or you had to argue for it over a few conversations. Both are fine answers. Claiming instant universal agreement usually reads as embellished.
This question is designed to catch candidates who default to "I proposed a solution" answers for everything. A good response names a specific moment where the client's stated request and their actual underlying need diverged, and the only way you found that gap was by asking a follow-up question instead of jumping straight to a fix.
Keep the mechanics concrete: what did they originally ask for, what did you notice in how they described the problem that made you probe further, and what did that follow-up question actually surface that changed the direction of the work.
Name the obstacle specifically, a key team member leaving mid-project, a vendor dependency falling through, requirements that changed after the timeline was already committed, and walk through the decision you made to keep the project on track rather than the general fact that "the team pulled together."
Interviewers weight this one on specificity. If your answer would work equally well with the obstacle swapped out for a different one, it's too generic to demonstrate real leadership under pressure.
Fill the 5-liter bucket completely, then pour it into the 3-liter bucket until that one is full. That leaves exactly 2 liters in the 5-liter bucket. Empty the 3-liter bucket, pour the remaining 2 liters into it, then fill the 5-liter bucket again and top off the 3-liter bucket, which only needs 1 more liter to fill. That leaves exactly 4 liters in the 5-liter bucket.
Puzzle questions like this show up occasionally in HR rounds, framed as testing structured problem-solving under pressure rather than any real math skill. The interviewer usually cares more about whether you talk through your reasoning out loud than whether you land the answer instantly.
Hard questions
9One clean approach keeps push expensive and pop cheap. On push, add the new element to an empty second queue, then dequeue everything from the first queue into the second one behind it, so the newest element ends up at the front. Swap the queue references and you're done.
from collections import deque
class StackFromQueues:
def __init__(self):
self.q1 = deque()
def push(self, x):
self.q1.appendleft(x) # simplest: put new element at the front
def pop(self):
return self.q1.popleft()Using a deque to fake "appendleft" like this is a bit of a shortcut versus the classic two-real-queues version, which is the answer interviewers actually want you to reason through: it costs O(n) per push and O(1) per pop, because every push has to re-rotate the whole queue to keep the newest item accessible first.
Because the graph is acyclic, a topological sort gives you a processing order where every node's dependencies are already resolved before you reach it. Process nodes in that order, and for each edge relax the longest-distance estimate the same way Bellman-Ford relaxes shortest distances, just maximizing instead of minimizing.
def longest_path(graph, topo_order):
dist = {node: float('-inf') for node in graph}
dist[topo_order[0]] = 0
for u in topo_order:
for v, weight in graph[u]:
if dist[u] + weight > dist[v]:
dist[v] = dist[u] + weight
return distThis runs in O(V + E), the same complexity as the topological sort itself, since the relaxation pass touches each edge exactly once.
The client sends a SYN packet with an initial sequence number. The server responds with a SYN-ACK, acknowledging the client's sequence number and sending its own. The client responds with an ACK, acknowledging the server's sequence number, and only then does the connection count as established.
Two steps aren't enough because both sides need to confirm they can both send and receive, not just that one direction works. A SYN followed by an ACK only proves the server heard the client. The third step proves the client heard the server back, so both sides have verifiably exchanged and acknowledged a starting sequence number before any real data moves, which is what makes TCP's reliable, ordered delivery guarantee possible in the first place.
Thrashing happens when a system spends more time swapping pages in and out of memory than actually executing processes, usually because too many processes are competing for too little physical memory and each one's working set doesn't fit. CPU utilization drops even though the system looks busy, because most of that activity is page faults, not real work.
Detection typically watches CPU utilization against the degree of multiprogramming, if CPU usage drops as more processes are added, that's the signature. Recovery means reducing the number of active processes, suspending some of them until memory pressure eases, rather than adding more processes to "help."
The increment operation, counter++, isn't atomic. It's actually three steps, read the current value, add one, write it back, and if two threads interleave those steps, one thread's increment can be silently overwritten by the other's, leaving the final count lower than expected. This is a classic race condition, and it won't show up reliably in testing, only under real concurrent load.
class Counter {
private int count = 0;
// unsafe: increment isn't atomic
void increment() { count++; }
}
class SafeCounter {
private final AtomicInteger count = new AtomicInteger(0);
void increment() { count.incrementAndGet(); } // atomic, no lock needed
}AtomicInteger uses a compare-and-swap loop internally instead of a lock, which is usually faster than synchronizing the whole method for a simple counter, though a synchronized block or method works too and is easier to reason about for anything more complex than a single variable.
This needs GROUP BY paired with HAVING, not WHERE, because the filter applies to an aggregated value, not to individual rows. WHERE runs before grouping happens and can't reference an aggregate function.
SELECT department_id, COUNT(*) AS employee_count
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5;Candidates who reach for WHERE COUNT(*) > 5 here get an immediate syntax error, and explaining why WHERE can't filter on an aggregate, versus HAVING which runs after the grouping, is really what this question is testing.
Interviewers use this to test whether you actually understood the system you worked on or just executed tickets inside it. A strong answer names the specific components, the data flow between them, and one honest tradeoff you made under a real constraint, deadline, team size, legacy code you inherited, not a textbook-perfect design.
The "what would you change" half matters as much as the description. Naming a real regret, a database schema that should have been normalized differently, a service boundary drawn in the wrong place, signals more seniority than pretending the original design had no flaws.
Pick a failure you actually owned some responsibility for, not one you can blame entirely on a client changing requirements or a vendor missing a deadline. Interviewers are testing whether you can be honest about your own miscalculation, not whether you've never had a project go sideways.
Structure it as: what you assumed going in that turned out wrong, the specific moment you realized it, and the concrete recovery step, renegotiating scope, bringing in a specialist, escalating early instead of late. "We recovered by communicating better" is the answer that gets a skeptical follow-up question. Naming the exact tactical decision you made is the one that doesn't.
Start with the data model: a jobs table with status, priority, retry_count, and next_run_at, and a separate worker pool that polls for the highest-priority eligible job, one whose next_run_at has passed and status is pending. Use a database-level row lock or a SELECT FOR UPDATE SKIP LOCKED pattern so multiple workers don't grab the same job simultaneously.
Retry logic needs exponential backoff, doubling the delay before next_run_at each time a job fails, up to a max retry count, after which the job moves to a dead-letter state instead of retrying forever. Priority levels are simplest as an integer column you sort by in the polling query, with a secondary sort on creation time so equal-priority jobs stay roughly FIFO.
How to prepare for an NTT Data interview
Treat the written test as its own separate prep track from the technical rounds, aptitude and reasoning questions reward pattern practice more than deep study, and a few timed practice sets the week before matter more than cramming algorithms. For the technical rounds, candidate reports consistently point at fundamentals over cleverness: know banker's algorithm and CPU scheduling well enough to explain them from scratch, not just recognize the name, and be ready to write a join or a second-highest-value query without a database in front of you.
For experienced hires, the project-discussion round deserves real rehearsal, not just familiarity. Pick your two most defensible projects and practice walking through the architecture out loud, including the one decision you'd change, before the interview, not during it. And if a group discussion round is part of your loop, know that interviewers are watching how you handle disagreement and airtime, not which side of the debate you land on.
Get the reps in before the real thing
LastRoundAI's mock interview mode runs live technical and behavioral rounds with real-time follow-up questions, useful for rehearsing the project-discussion format specifically, where a rehearsed script falls apart the moment someone asks "why that approach and not the obvious alternative." The free plan includes 15 credits a month that reset monthly, and Starter is $19/mo if a handful of sessions isn't enough runway.
Once your answers hold up under a follow-up, Auto-Apply queues tailored applications to consulting and IT services roles for your review, 10 a month on the free plan, up to 400 a month on the Ultimate plan, and nothing goes out until you approve it.
Questions about either product go to contact@lastroundai.com.
How this list was built
Worth being straight about where these questions come from, because plenty of pages in this category are not. The set was compiled from a research pass across official documentation, vendor release notes, published engineering writing and public discussion of hiring processes, then cross-checked against the current version of each technology so nothing here describes behaviour that has since changed.
What that means in practice: these are the questions the material supports as reasonable and current for this role, not a transcript of any one company's loop. We have not sat in on your interview and we are not going to claim we have. Treat the list as well-sourced preparation rather than a leaked question bank, and expect your panel to phrase things their own way.
If you spot something out of date, tell us at contact@lastroundai.com and we will fix it.
Frequently asked questions
Does NTT Data ask coding questions in the interview?
Usually yes, though at a moderate level rather than competitive-programming difficulty. Expect array and string manipulation, basic recursion and SQL. Being able to explain your approach out loud carries real weight, because the interviewer is assessing trainability as much as correctness.
What happens in the NTT Data HR round?
Relocation flexibility, shift willingness, the service agreement or bond if one applies, and why you want this company specifically. It is largely a fit and commitment check, but people do get rejected here, usually for appearing uninterested or for contradicting something on their form.
How long does the NTT Data hiring process take?
Commonly two to six weeks from first assessment to offer, though campus drives can compress it to a few days and lateral roles sometimes stretch longer. Silence in between is normal and is not usually a signal either way.
How many rounds does the NTT Data interview have?
Most NTT Data processes run an online aptitude and technical assessment, then one or two technical interviews, then an HR round. Lateral hiring often drops the aptitude test and goes straight to technical. The exact shape varies by campus drive versus off-campus, so confirm with your recruiter rather than assuming.
Is the NTT Data aptitude test hard to clear?
It is more about pace than difficulty. The quantitative and logical sections are standard campus-placement material, but the time per question is tight, so accuracy under time pressure is what actually filters people out. Practising with a clock matters more than learning new topics.
