A candidate applying for an Associate Software Engineer role at Nagarro's Gurugram office described a hiring loop with four distinct stages inside a single day: an online MCQ test on the Mettle platform, a 75 minute pen and paper coding round with three problems, a technical interview, and a short HR round, with the field narrowing from roughly 100 candidates down to one offer by the end (AmbitionBox candidate interview reports). That funnel shape, wide at the top and brutal by round three, shows up again and again in reports from campus and lateral hires alike.
Nagarro calls its hiring approach a "reverse application" process and builds its whole employee pitch around an acronym it uses internally and externally: CARING, for challenging projects, giving back, flat hierarchy, education, fun at work, and work-life balance (Nagarro careers page). That culture language isn't just marketing copy for this interview loop. Interviewers at Nagarro ask about it directly, and HR rounds lean on questions about ownership and working without a rigid hierarchy more than the average IT services firm does.
This page covers the questions candidates actually report facing across Nagarro's online assessment, coding round, technical interview, and HR round, plus the system design and domain questions that show up once you're past entry level. Where the public record of candidate reports is thin, mostly senior system design rounds, this page says so rather than inventing specifics.
Round 1: Online MCQ and aptitude assessment
Nagarro runs its first screen as a computer-based test, commonly on the Mettle platform, split into a technical MCQ section and an aptitude section, with a plus-4 minus-1 scoring scheme that punishes guessing on the technical half more than most campus tests do.
Easy questions
16Time complexity describes how the running time of an algorithm grows as the input size grows, expressed with Big O notation as an upper bound. Nagarro's MCQ round asks you to identify the complexity of a given loop or recursive call rather than write the code yourself, because at the screening stage the company is filtering for whether you can read code and reason about its cost, not whether you can produce working syntax under time pressure.
A nested loop over the same array is O(n squared) even if the inner loop only runs on some iterations, because worst case still dominates the classification. A recursive Fibonacci without memoization is O(2^n), which is the kind of question that trips people up because the code looks deceptively short for how expensive it actually is.
An array stores elements in contiguous memory with O(1) index access but O(n) insertion or deletion in the middle, since everything after the insertion point has to shift. A linked list stores elements as nodes with pointers to the next node, giving O(1) insertion and deletion once you have a reference to the right spot, but O(n) access to an arbitrary index since you have to walk the chain.
Pick an array when you read far more than you insert or delete, and you know roughly how large the collection gets. Pick a linked list when insertions and deletions in the middle of the collection are frequent and index access is rare, a task queue being reordered, for instance.
Normalization is the process of organizing a relational database's tables and columns to reduce redundant data and avoid update anomalies, where the same fact stored in two places can drift out of sync when one copy gets updated and the other doesn't. Each normal form addresses a specific kind of redundancy, first normal form removes repeating groups within a single column, second normal form removes partial dependency on part of a composite key, third normal form removes columns that depend on another non-key column instead of the key itself.
In practice, most production schemas aim for third normal form and then deliberately denormalize specific tables for read performance, once the redundancy cost is understood rather than accidental.
A process is an independent execution unit with its own memory space, file handles, and system resources, isolated from other processes unless it explicitly uses interprocess communication. A thread is a unit of execution inside a process that shares that process's memory space and resources with every other thread in the same process, which makes threads cheaper to create and switch between but introduces the risk of two threads reading or writing the same memory at the same time.
That shared memory is exactly why thread safety, locks, and race conditions matter for threads and don't come up the same way across processes, where the operating system's memory isolation already prevents one process from corrupting another's state directly.
A primary key uniquely identifies each row in a table, cannot contain null values, and a table can only have one. A unique key also enforces that every value in the column is distinct across rows, but it allows a single null value (in most database engines) and a table can have several unique keys alongside its one primary key.
In practice, a primary key is usually the column other tables reference with a foreign key, while a unique key is used to enforce a business rule, an email column that must be unique per user, for example, without making that column the table's identity.
Split the sentence into words, then for each word check its length. If the word is at least four characters, split it at index length divided by two using integer division, and join the two halves with a space. Words shorter than four characters pass through unchanged. Finally join everything back together with single spaces.
def split_long_words(sentence):
words = sentence.split()
result = []
for w in words:
if len(w) >= 4:
mid = len(w) // 2
result.append(w[:mid] + " " + w[mid:])
else:
result.append(w)
return " ".join(result)
print(split_long_words("Hello I am Mike Saunders"))
# "Hel lo I am Mi ke Saun ders"The trap here is off-by-one errors on the split index for odd-length words. Walking through a five-letter word by hand before coding catches that immediately.
Use two pointers, one moving one node at a time (slow) and one moving two nodes at a time (fast). When the fast pointer reaches the end of the list, the slow pointer sits at the middle. For an even-length list this convention lands on the second of the two middle nodes, which is worth stating out loud since interviewers sometimes want the first one instead.
def find_middle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slowWalk the list once, keeping track of the previous node, the current node, and the next node before you overwrite anything. At each step, point current's next back at previous, then advance all three pointers forward by one position.
def reverse_list(head):
prev = None
current = head
while current:
next_node = current.next
current.next = prev
prev = current
current = next_node
return prevBreadth-first search explores a graph level by level using a queue, visiting every neighbor of the current node before moving further out, which makes it the right choice whenever you need the shortest path in an unweighted graph, since the first time BFS reaches a node is guaranteed to be via the shortest path. Depth-first search explores as far as possible down one branch before backtracking, using a stack or recursion, which fits problems about reachability, cycle detection, or exploring all paths rather than the shortest one.
A practical tell: if the question mentions "shortest" or "minimum number of steps," reach for BFS. If it's about "does a path exist" or "find all connected components," DFS is usually simpler to write and just as correct.
A binary search tree stores values such that for every node, all values in its left subtree are smaller and all values in its right subtree are larger. That invariant is what lets search, insertion, and deletion run in O(log h) time relative to the tree's height, since at every node you can eliminate half the remaining search space by comparing against just that one node.
The catch is that the invariant alone doesn't guarantee O(log n) overall, a BST built by inserting already-sorted data degenerates into a straight line, effectively a linked list, with O(n) operations. That's exactly why self-balancing variants, AVL trees or red-black trees, exist, they maintain the same search invariant while also bounding the tree's height.
An abstract class can hold both fully implemented methods and abstract ones that subclasses must implement, plus state in the form of instance fields, and a class can only extend one abstract class. An interface (in languages that traditionally distinguish the two, Java before default methods, C#) declares only method signatures with no implementation and no state, and a class can implement several interfaces at once.
Choose an abstract class when subclasses genuinely share common state or behavior worth inheriting, and you're comfortable with the single-inheritance constraint. Choose an interface when you're defining a contract that unrelated classes need to satisfy, a Comparable or Serializable style capability, without forcing a shared ancestor between them.
The O(n squared) approach checks every pair with nested loops. The better approach uses a hash set: scan once, and for each element check whether target minus that element is already in the set. If it is, you've found a pair; either way, add the current element to the set and move on. This runs in a single O(n) pass.
def find_pairs(arr, target):
seen = set()
pairs = []
for n in arr:
complement = target - n
if complement in seen:
pairs.append((complement, n))
seen.add(n)
return pairsThis question comes directly out of Nagarro's stated CARING value around work-life balance and flexibility for personal appointments. Interviewers are checking for a realistic, specific answer rather than either extreme, someone who claims they never disconnect, or someone who signals they're not invested in the work at all.
A grounded answer names concrete boundaries, protected focus hours, how you handle an urgent issue outside normal hours versus a non-urgent one that can wait, and connects it back to sustaining good work over years rather than framing balance as something in tension with being a strong contributor.
This maps to the "education" strand of CARING, continuous learning as an expectation rather than an optional perk. The strongest version of this answer is specific about the learning method, not just "I read the docs," but what you actually did to go from zero to functional, a small throwaway prototype, pairing with someone who already knew the area, a specific resource that unblocked you.
Naming a concrete deadline or constraint that forced the pace of learning, rather than presenting it as leisurely self-improvement, makes the story land as real work rather than a hobby project you're retrofitting into an interview answer.
A generic answer about wanting "growth opportunities" or "a challenging environment" applies to any company and signals you didn't research this one specifically. A stronger answer references something concrete about Nagarro, its non-hierarchical structure if that genuinely appeals to you over a more traditional reporting chain, its positioning as a digital engineering firm working across a range of client industries rather than a single product, or a specific technology area the company is known to work in that matches what you want to do next.
The honesty test here matters more than the polish: if the real reason is compensation, location, or timing, it's fine to name that as one factor while still connecting it to something substantive about the role or company.
This is a logistics question with real elimination power, candidates in reported loops describe it as a direct, practical check rather than a soft opener. Give a direct, honest answer rather than a noncommittal one, since a vague "I think so" tends to get treated as a maybe and can stall an otherwise strong candidacy at the finish line.
If there are real constraints, a family situation, a visa timeline, a partner's job, naming them plainly and asking what flexibility exists is a better outcome than agreeing to terms you're not actually able to meet.
Medium questions
18== performs type coercion before comparing, converting operands to a common type if they differ, while === compares both value and type without any coercion. That means "5" == 5 evaluates to true because the string gets coerced to a number, but "5" === 5 evaluates to false because a string and a number are never the same type regardless of value.
console.log(0 == "0"); // true, "0" coerces to 0
console.log(0 == ""); // true, "" coerces to 0
console.log(0 == []); // true, [] coerces to 0 through a chain of conversions
console.log(0 === "0"); // false, different typesThe reason MCQ writers like this question is that the coercion rules aren't always intuitive, an empty array loosely equals 0, which surprises people who assume loose equality just means "close enough."
This is backtracking with a running remainder. At each step, try including the current candidate again (since reuse is allowed), or move on to the next candidate. The key detail candidates miss is sorting the input first and skipping duplicates at the same recursion depth, which is what actually keeps the output combinations unique when the input has repeated values.
def combination_sum(candidates, target):
candidates.sort()
result = []
def backtrack(start, remaining, path):
if remaining == 0:
result.append(list(path))
return
for i in range(start, len(candidates)):
if candidates[i] > remaining:
break
path.append(candidates[i])
backtrack(i, remaining - candidates[i], path) # reuse allowed, so start stays i
path.pop()
backtrack(0, target, [])
return resultNagarro interviewers reportedly follow up by asking what changes if each number can only be used once. The fix is to advance start to i plus 1 in the recursive call instead of leaving it at i, and skip over duplicate values at the same level to avoid producing the same combination twice.
Track the two largest values and the two smallest (most negative) values in a single pass. The answer is the larger of the product of the top two and the product of the bottom two, since two large negatives multiply into a large positive, which candidates who only track the top two values miss entirely.
def max_pair_product(arr):
max1 = max2 = float("-inf")
min1 = min2 = float("inf")
for n in arr:
if n > max1:
max2, max1 = max1, n
elif n > max2:
max2 = n
if n < min1:
min2, min1 = min1, n
elif n < min2:
min2 = n
return max(max1 * max2, min1 * min2)Top-down starts from the original problem and recurses into smaller subproblems, caching results as it goes so the same subproblem is never recomputed, memoization. Bottom-up starts from the smallest subproblems and builds up to the original problem iteratively, filling a table in an order that guarantees every value a step depends on is already computed.
Fibonacci is the standard example. Top-down recurses fib(n minus 1) plus fib(n minus 2), caching each result in a dictionary keyed by n. Bottom-up fills an array from index 0 upward, dp[i] equals dp[i minus 1] plus dp[i minus 2], with no recursion or call stack overhead at all. Bottom-up is usually faster in practice for problems where you need every subproblem anyway, since it avoids recursion overhead, but top-down is easier to write correctly when only a subset of subproblems actually get visited.
Floyd's cycle detection, the same slow and fast pointer technique used to find the middle, detects a cycle because if one exists, the fast pointer eventually laps the slow pointer and they meet inside the loop. If they never meet, fast reaches null and there's no cycle.
Finding where the cycle starts takes one more step once slow and fast meet: reset one pointer to the head and move both pointers one step at a time from there. Wherever they meet the second time is the start of the cycle. This works because of the distance relationship between the meeting point, the cycle start, and the head, provable with basic algebra on the distances each pointer traveled, but most interviewers accept "I know this works" and want to see it implemented correctly more than they want a from-scratch proof.
Use a running prefix sum and a hash set. As you scan left to right, keep a running total. If running total minus target has already been seen as a prefix sum earlier in the scan, the subarray between those two points sums to the target. This is a single O(n) pass instead of the naive O(n squared) that checks every pair of start and end indices.
def has_subarray_with_sum(arr, target):
seen = {0}
running = 0
for n in arr:
running += n
if running - target in seen:
return True
seen.add(running)
return FalseThis is the same prefix sum trick that solves a whole family of subarray problems, and interviewers who ask it once will often follow up with a variant, count all subarrays with the sum instead of just detecting one, which only needs a dictionary of counts instead of a set.
The honest answer interviewers want is a recognizable signal: the problem has overlapping subproblems, the same smaller computation gets needed more than once if you solve it the brute force way, and it has optimal substructure, the best solution to the whole problem can be built from best solutions to its pieces. Recognizing that signal before writing any code is what separates someone who reaches for DP because the interviewer hinted at it from someone who'd have found it unprompted.
A concrete tell in this specific problem set: if a brute force recursive solution recomputes the same subrange of a string or the same remaining target value multiple times across different call paths, that repetition is the overlapping subproblem signal. Draw the recursion tree for a small input by hand, count how many times the same argument set appears, and that count is your answer for why DP applies here.
State the complexity precisely, both the worst case and, if it differs meaningfully, the average case, and be ready to justify each term rather than reciting the final answer. For a nested loop solution, walk through why each loop contributes its factor. For a solution with a hash map or heap, name the operation, insertion, lookup, and its actual complexity for that specific structure rather than assuming O(1) for everything.
"Can you reduce it further" is often not really asking for a better algorithm, it's asking whether you understand the lower bound for the problem itself. If comparison-based sorting is involved, that lower bound is n log n and no amount of cleverness beats it without changing the problem's assumptions, radix sort assumes bounded integer keys, for instance. Saying "I don't think this can go lower because of X" when X is actually true is a stronger answer than guessing at an optimization that doesn't exist.
A hash map computes a hash of the key, maps that hash to a bucket index, and stores the key-value pair in that bucket. Lookup, insertion, and deletion are all O(1) on average because a good hash function spreads keys evenly across buckets, so each bucket holds very few entries.
The guarantee breaks down when many keys collide into the same bucket, either from a poor hash function or from an adversarial or unlucky input distribution, at which point a bucket degrades toward a linked list and lookup in that bucket becomes O(n) in the worst case. Some language implementations mitigate this by converting a bucket to a balanced tree once it exceeds a size threshold, capping the worst case at O(log n) instead of O(n), which is worth mentioning if the interviewer pushes on worst case behavior specifically.
This question is really testing whether the project on your resume is actually yours, in the sense that you can explain a decision you made and its downside, not just describe what the finished thing does. A strong answer names a specific constraint, time, an existing library choice, a team decision you inherited, describes the alternative you didn't take, and states plainly what you'd change with the knowledge you have now.
Vague answers here ("we used React because it's popular") read as if the project details were memorized rather than lived. Specific answers ("we chose polling over websockets because our infra team hadn't set up socket support yet, and in hindsight the polling interval caused a noticeable lag we'd have avoided with websockets") read as real experience, whether the project was large or small.
Quicksort picks a pivot element, partitions the array so everything smaller than the pivot ends up to its left and everything larger ends up to its right, then recursively sorts each side. On average, a random or well-chosen pivot splits the array roughly in half each time, giving the same log n recursion depth as merge sort, with n work at each level, hence O(n log n).
The worst case happens when the pivot choice consistently produces a wildly unbalanced split, one side with n minus 1 elements and the other with zero. Choosing the first or last element as the pivot on an already sorted array triggers exactly this, since every partition puts everything on one side. That degrades the recursion depth to n instead of log n, giving O(n squared) overall. Randomized pivot selection, or choosing the median of three candidates, is the standard fix that makes the worst case practically unreachable rather than eliminating it in theory.
Vertical scaling adds more resources, CPU, memory, disk, to a single machine. Horizontal scaling adds more machines and distributes the load across them. Horizontal scaling is generally considered more resilient, since it removes a single point of failure and has no hard ceiling the way a single machine eventually does, but it introduces real complexity, load balancing, data consistency across nodes, network calls that didn't used to exist.
Vertical scaling wins for workloads that are hard to shard or distribute cleanly, a single large in-memory graph computation, or a database with heavy join workloads across data that doesn't partition naturally. It's also the right early-stage answer for a system whose current load a bigger single machine comfortably handles, since horizontal scaling's operational overhead isn't worth paying before it's needed.
Put a cache, typically an in-memory store like Redis, in front of the database for the specific reads that dominate traffic, keyed in a way that matches the actual query pattern rather than caching everything indiscriminately. A time-based expiry (TTL) is the simplest invalidation strategy and works well when slightly stale data is acceptable.
The real risk to flag is cache invalidation on writes: if an underlying record changes and the cache isn't explicitly invalidated or updated at write time, a TTL-only strategy means clients can see stale data for up to the full TTL window after every update. Explicit invalidation on write closes that gap but adds coupling between every write path and the cache layer, which is exactly the kind of trade-off worth naming rather than glossing over, since "there are only two hard things in computer science, cache invalidation and naming things" is a joke precisely because both are genuinely hard.
A relational database fits data with well-defined relationships and a need for strong consistency guarantees across those relationships, ACID transactions, foreign key constraints, complex joins across normalized tables. A document store fits data that's naturally hierarchical or varies in shape between records, and where the access pattern is usually "fetch this whole document by its id" rather than joining across many entities.
The honest answer acknowledges this isn't purely technical, team familiarity, existing operational tooling, and what the rest of the client's stack already uses matter in a consulting context like Nagarro's, where a new service often has to fit into an existing client environment rather than being greenfield. Naming that constraint, instead of pretending every database choice happens in a vacuum, tends to land well in a panel with actual delivery experience.
This question is a direct probe at Nagarro's stated flat hierarchy, where the company says it wants employees to be "brave, creative, entrepreneurial, agile and responsible" rather than waiting for permission. A strong answer picks a real, specific decision, states the risk of getting it wrong, and is honest about the outcome, including if it didn't go perfectly.
What reads poorly here is a story where "I made the decision" actually means "I did what was obviously the only sane option," since that isn't really a decision under ambiguity. The stronger version of this story involves a genuine judgment call where a reasonable colleague might have chosen differently, and you can explain why you chose the way you did.
Nagarro's careers language specifically distinguishes "challenging" from merely stressful, framing it around solving problems that push the team to build something new rather than grinding through a known solution under pressure. The distinction is worth taking seriously in your answer: a deadline crunch on a CRUD feature isn't the same story as a project where the actual technical approach wasn't obvious at the start.
Pick a project where you can describe the specific unknown you had to resolve, an algorithm that didn't exist yet for your use case, an integration between systems that had never talked to each other, a performance ceiling nobody had broken before on that codebase, and walk through how you got from not knowing to knowing.
In a flat structure without much hierarchy to lean on for enforcement, peer feedback quality matters more than it does in a heavily managed org, which is why this comes up. The answer worth giving names a specific piece of feedback, what made it land or not land, and one concrete behavior that changed afterward, rather than a generic "communication is important" platitude.
Giving an example where you were on the receiving end and it stung a little before it helped is usually more convincing than a story where you were only ever the one delivering wisdom to others.
This question, reported directly by candidates in HR rounds, is checking resilience and self-awareness rather than looking for a flawless track record. A specific, honest example, a rejected application, a project pitch that didn't get approved, a promotion that went to someone else, followed by what you actually did afterward, reads far better than claiming you've never really been rejected.
What the interviewer is listening for underneath the story is whether you took something useful away from the setback or just waited for it to stop stinging, since the second pattern tends to repeat.
Hard questions
5A plain palindrome check is a two-pointer walk from both ends toward the middle, comparing characters and stopping on the first mismatch. A k-palindrome check is a different problem entirely: you need the minimum number of character deletions required to turn the string into a palindrome, and then compare that number against k.
The clean way to compute minimum deletions is through the longest palindromic subsequence. If a string has length n and its longest palindromic subsequence has length L, the minimum deletions needed is n minus L, since every character not in that subsequence has to go. Longest palindromic subsequence itself is a classic dynamic programming problem, solved by comparing the string against its reverse and running a longest common subsequence on the pair, which brings the naive exponential brute force reported by candidates down to O(n squared) time and space.
def longest_palindromic_subsequence(s):
n = len(s)
dp = [[0] * n for _ in range(n)]
for i in range(n - 1, -1, -1):
dp[i][i] = 1
for j in range(i + 1, n):
if s[i] == s[j]:
dp[i][j] = dp[i + 1][j - 1] + 2
else:
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
return dp[0][n - 1]
def is_k_palindrome(s, k):
lps = longest_palindromic_subsequence(s)
return len(s) - lps <= kMaintain a min-heap of size k. Push the first k elements onto the heap, then for every remaining element, compare it against the heap's minimum, if it's larger, pop the minimum and push the new element in. By the end, the heap holds exactly the k largest elements, and the whole scan runs in O(n log k) time, which beats sorting the entire array in O(n log n) whenever k is meaningfully smaller than n.
import heapq
def k_largest(arr, k):
heap = arr[:k]
heapq.heapify(heap)
for n in arr[k:]:
if n > heap[0]:
heapq.heapreplace(heap, n)
return heapA naive recursive solution to a problem like k-palindrome, trying every possible deletion at every position without caching, runs in exponential time, roughly 2^n, because each character offers a branch to keep or delete and the recursion explores both at every level. That's the complexity candidates reportedly hit first and get stuck defending under follow-up questions.
Adding memoization to the same recursive structure, caching results keyed by the substring bounds being considered, brings it down to O(n squared) time with O(n squared) space for the memo table, since there are only n squared distinct substring bound pairs to ever compute. An iterative bottom-up table fill achieves the identical O(n squared) time and space, but avoids the call stack depth risk that a memoized recursive solution has on very long strings, which is the detail that separates someone who's only memorized the recurrence from someone who understands why the complexity changed.
A deadlock is a state where two or more threads or processes are each waiting for a resource the other holds, and none can proceed. Four conditions all have to be true simultaneously for a deadlock to occur: mutual exclusion, a resource can only be held by one thread at a time; hold and wait, a thread holding one resource is waiting on another; no preemption, a resource can't be forcibly taken away from a thread holding it; and circular wait, a cycle exists in the graph of threads waiting on each other's resources.
Breaking any one of those four conditions prevents deadlock. In practice, the most common fix is attacking circular wait directly, by imposing a strict, global ordering on lock acquisition so every thread requests locks in the same sequence, which makes a cycle structurally impossible regardless of timing.
This is testing whether you can operate inside "disagree and commit" without either silently resenting the decision or quietly undermining it. A strong answer separates two things clearly: whether you raised the disagreement before the decision was finalized, and what you did once it was made regardless of whether your view won.
The weakest version of this answer either claims you're always right in hindsight, or describes a pattern of going along with decisions you privately think are wrong without ever actually voicing the disagreement at the point it could have changed anything. Neither shows the judgment a flat, high-ownership structure like Nagarro describes actually needs from its people.
Real-time scenario questions
4Maintain a second stack alongside the main one that tracks the minimum seen so far at each point in time. On every push, also push the smaller of the new value and the current minimum onto the min stack. On every pop, pop from both stacks together. getMin just reads the top of the min stack.
class MinStack:
def __init__(self):
self.stack = []
self.min_stack = []
def push(self, val):
self.stack.append(val)
current_min = val if not self.min_stack else min(val, self.min_stack[-1])
self.min_stack.append(current_min)
def pop(self):
self.stack.pop()
self.min_stack.pop()
def get_min(self):
return self.min_stack[-1]Interviewers use this to test whether you reach for a second data structure without being told to, since the naive answer, scan the stack every time getMin is called, is O(n) and clearly not what the O(1) requirement is asking for.
The core of a URL shortener is a mapping from a short code to a long URL, so the two operations that matter are: generate a unique short code for a new long URL, and redirect a short code back to its original URL fast. Generation can use a counter encoded in base 62, or a hash of the URL truncated and checked for collisions, the counter approach is simpler to reason about and avoids collision handling entirely at the cost of needing a coordinated counter across servers.
Redirection needs to be very fast and read-heavy, so a cache in front of the database, keyed by short code, absorbs most traffic before it ever hits persistent storage. Persistent storage itself can be a simple key-value store since there's no need for complex queries, just point lookups by short code. The parts worth discussing further if pushed: how you'd handle custom aliases, how you'd expire old links, and how you'd shard the counter or key space once a single database can't hold the traffic.
A token bucket is usually the practical default: each client gets a bucket that refills at a fixed rate up to a maximum capacity, and each request consumes one token, rejected if the bucket is empty. It allows short bursts up to the bucket size while still enforcing a long-run average rate, which fits real traffic patterns better than a strict fixed window.
A fixed window counter is simpler to implement, just count requests per client in the current time window and reset at the boundary, but it has a known edge case: a client can send a full window's worth of requests right at the end of one window and another full window's worth right at the start of the next, doubling the effective rate right at the boundary. A sliding window log or sliding window counter fixes that edge case at the cost of more state per client. Which one to pick depends on whether the interviewer cares about implementation simplicity or correctness at the boundary, and saying that trade-off out loud matters more than picking the "right" one.
The two common patterns are an append-only audit table that records every change as a new row, storing the entity id, the field changed, the old value, the new value, who made the change, and a timestamp, or a versioned table where the entity itself carries a version number and old versions are kept rather than overwritten.
An append-only audit log is cheaper to write and easy to reason about for compliance purposes, since nothing is ever mutated, but reconstructing "what did this record look like at time X" requires replaying every change from the beginning or from the nearest snapshot. A versioned table makes point-in-time reads cheaper at the cost of more storage and more complex writes, since every update becomes an insert of a new version rather than an in-place update. Given that Nagarro's technical panels reportedly lean on real project context, the strongest answer here connects the choice to an actual constraint, write volume, compliance requirement, query pattern, rather than picking one in the abstract.
How to prepare for a Nagarro interview
Time yourself on the coding round specifically. Three problems in 75 minutes is roughly 25 minutes each, and candidate reports describe the third problem, usually the backtracking or DP one, as the one that eats time if you haven't pattern-matched it quickly. Practicing a timed set of three medium problems back to back, not one problem at a time with unlimited time, is a closer simulation of the actual pressure than most casual LeetCode practice sessions are.
For the technical round, prepare to defend your coding round answers out loud a second time, in a different room, to a different person, since that's exactly what candidates report happening. Rehearse explaining why a solution uses DP, what the actual time complexity is, and whether it can be improved, as a script you can give cleanly rather than reasoning it out live for the first time under a second round of pressure.
For the behavioral and HR rounds, read Nagarro's own CARING framework before the interview and have one real, specific story ready for each letter: a challenging project, a time you gave back beyond your assigned scope, a decision you made without waiting on hierarchy, something you learned quickly, a moment work-life balance actually mattered to a call you made. Vague answers to values questions are easy for an experienced HR interviewer to spot.
Get the reps in before the real thing
Reading through reported questions is useful for knowing what's coming. It's a different thing entirely to explain your k-palindrome solution's complexity out loud, under a clock, to someone who immediately asks "can you do better." LastRoundAI's mock interview mode runs live coding and follow-up rounds in your browser, and the free plan includes 15 credits a month that reset monthly instead of piling up unused.
Once your answers hold up under a real follow-up question, the harder part of the search is usually just getting your resume in front of enough roles at firms like Nagarro that actually run a structured technical loop instead of a single generic screen. Auto-Apply queues tailored applications 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. That's the only inbox we check.
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
What should freshers focus on for a Nagarro interview?
One programming language you can write confidently on paper, core CS fundamentals (OOP, DBMS, operating systems, networks), and a project you can explain end to end. Freshers who can defend their own project in detail consistently do better than those who list five projects shallowly.
Does Nagarro 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 Nagarro 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 Nagarro 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.
