A candidate posting a 2024 off-campus SDE interview writeup on GeeksforGeeks described the first stage as "a rapid-fire round of 25 questions on data structures and computer science fundamentals, each demanding a solution within a minute," followed by two coding problems inside a 90-minute window. That pace shows up again and again in reports from Walmart Global Tech loops. There isn't one script. A software engineer candidate and a data analyst candidate at the same company will sit through a different number of rounds, on different platforms, with different weighting on system design versus SQL. What's consistent is the shape: an online assessment gate, two or more technical rounds that mix DSA with domain-specific questions (Java, Spring, SQL, or product sense depending on the role), a hiring-manager conversation that always circles back to "why Walmart," and a values-based behavioral round that Walmart runs more formally than most retailers its size.
Glassdoor's aggregate data on the Software Engineer track puts the difficulty at 2.8 out of 5 and the positive-experience rate at 48%, with candidates typically going through 3 rounds and an average time-to-hire of 20 days (Glassdoor). That 48% figure is lower than most FAANG-adjacent companies report, and candidate writeups point to a specific reason: Walmart Global Tech's coding rounds run on HackerRank with a locked-down environment, no internet, sometimes proctored in an actual office rather than remote, which trips up people used to a more conversational whiteboard format.
This page pulls together the questions candidates actually report across the online assessment, the coding and system-design rounds, low-level design, core CS fundamentals, and the behavioral and hiring-manager stages, plus a shorter path through the product and data-analyst tracks where the process diverges. Where a round's real content was thin in what candidates share publicly, that's noted rather than filled in with guesses.
The online assessment: MCQs plus HackerRank coding
Most SDE and Global Tech applicants hit this gate first. Reports converge on a structure of roughly 10 aptitude and CS-fundamentals MCQs plus 2-3 coding problems, timed tightly and taken in a locked browser or, for some campus drives, in a physical testing room with no internet access (GeeksforGeeks, Walmart Labs interview experience).
Easy questions
14The OA candidates describe most often has two parts. The first is a block of multiple-choice questions covering quantitative aptitude, logical reasoning, verbal ability, and CS fundamentals like OS, DBMS, and networking basics, usually around 10 questions with a strict per-question timer. The second is 2-3 coding problems on data structures and algorithms, sometimes with a dynamic programming problem specifically, run through HackerRank or HackerEarth depending on the hiring cycle.
Partial credit on the coding section usually comes from test cases passed rather than an all-or-nothing grade, so a solution that handles the common case but misses an edge case still earns something. The MCQ section is scored separately and candidates report it acts as a cutoff before the coding submissions get reviewed at all, so rushing through fundamentals questions to save time for coding is a real risk, not just a theory.
Floyd's cycle detection: a slow pointer moves one node at a time, a fast pointer moves two. If they meet, there's a cycle. To find the entry point, reset one pointer to the head and advance both one step at a time; they meet exactly at the cycle's start, which follows from the distance math between the meeting point and the head.
def detect_cycle_start(head):
slow = fast = head
while fast and fast.next:
slow, fast = slow.next, fast.next.next
if slow == fast:
ptr = head
while ptr != slow:
ptr, slow = ptr.next, slow.next
return ptr
return NoneThe straightforward version uses DISTINCT to collapse duplicate salaries before ranking, since a naive OFFSET-based approach breaks the moment two employees tie for the top salary.
SELECT MAX(salary) AS second_highest
FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);A window-function version using DENSE_RANK() generalizes better if the interviewer follows up asking for the Nth highest instead of just the second, which happens often enough that it's worth mentioning even if you write the simpler subquery first.
Sliding window with a set or a map of last-seen index. Expand the right edge, and whenever a repeat shows up inside the current window, shrink the left edge past the previous occurrence instead of resetting the whole window to empty, which is the shortcut that keeps this at O(n) instead of O(n²).
def longest_unique_substring(s):
last_seen = {}
left = longest = 0
for right, ch in enumerate(s):
if ch in last_seen and last_seen[ch] >= left:
left = last_seen[ch] + 1
last_seen[ch] = right
longest = max(longest, right - left + 1)
return longestTwo pointers, one at each end, is the correct answer specifically because the array is sorted. Move the left pointer up when the sum is too small, move the right pointer down when the sum is too large, and stop when they meet or cross. Using a hash set instead works too but throws away the sorted-order advantage that gets you O(1) extra space here.
def two_sum_sorted(nums, target):
left, right = 0, len(nums) - 1
while left < right:
total = nums[left] + nums[right]
if total == target:
return [left, right]
elif total < target:
left += 1
else:
right -= 1
return []This one's a warm-up more than a real test, but it still separates candidates who reason from first principles from ones who've memorized a template. Base62-encode an auto-incrementing ID to get a short, collision-free code, store the mapping in a key-value store, and serve reads from a cache since reads massively outnumber writes for any shortener that gets real traffic.
ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
def encode(num):
if num == 0:
return ALPHABET[0]
chars = []
while num:
num, rem = divmod(num, 62)
chars.append(ALPHABET[rem])
return ''.join(reversed(chars))A base Vehicle class or interface with subtypes for car, motorcycle, and truck, a ParkingSpot class sized for specific vehicle types, and a ParkingLot that owns a collection of levels, each with its own spots. The interesting design decision is whether a `ParkingLot` assigns spots itself or delegates to a `SpotAssignmentStrategy`, which matters the moment the interviewer asks how you'd add a new rule like "compact cars can use motorcycle spots" without touching the core allocation logic.
Polymorphism means the same method call behaves differently depending on the actual runtime type of the object it's called on, decided at the interface or superclass level in the code but resolved at runtime. A payment processing service that accepts a `PaymentMethod` interface and calls `.charge()` on it doesn't need to know whether it's holding a `CreditCardPayment`, a `WalletPayment`, or a `GiftCardPayment`, each implements `.charge()` differently, and the calling code stays identical regardless.
The practical payoff isn't academic. Adding a new payment type later doesn't require touching the checkout flow's code at all, only adding a new class that satisfies the existing interface, which is the same open-closed idea that shows up again in the low-level design round.
This is a self-join: join the employee table to itself, matching each employee's manager ID against another row's employee ID, then filter for a higher salary on the employee side.
SELECT e.name AS employee, m.name AS manager
FROM employees e
JOIN employees m ON e.manager_id = m.id
WHERE e.salary > m.salary;Pick a disagreement with real stakes, not a trivial style preference. The strongest answers show you made your case with evidence, a benchmark, a production incident, a cost comparison, rather than just asserting an opinion louder, and that you were genuinely willing to update your position if the other person's evidence was stronger.
What interviewers are actually screening for here is whether disagreement damaged the working relationship afterward or not. Closing the story with how you and that teammate worked together on the next project is worth more than a clean "and I was right" ending.
Pick a story with an actual deadline attached, a production outage, a launch date that couldn't move, not a self-imposed one. Walk through the triage: what you checked first, what you ruled out, and why, since the reasoning process under pressure is what's actually being evaluated here, not just that the problem eventually got solved.
Specifics beat generalities. Name the actual technology, how long you had, and what your first concrete step was, reading the official docs, pairing with someone who already knew it, building a small throwaway project first. The follow-up worth anticipating: what would you do differently if you had to ramp up on something similar again next month.
The weak version of this answer talks about Walmart's size or revenue as if that alone were a reason to work anywhere. A stronger answer connects to something specific about the problems Walmart Global Tech actually works on, supply chain at a scale most companies never touch, or an omnichannel problem you find genuinely interesting, and ties that to something concrete in your own background rather than reciting the company's mission statement back at them.
Pick one project, not a tour of everything you've ever done, and go deep on it: the problem, your specific role versus the rest of the team's, the hardest decision you made, and what you'd do differently with hindsight. A hiring manager remembers one well-told story far better than five shallow ones, and the follow-up questions almost always dig into whatever project you chose to lead with.
Medium questions
21This is a direct variant of the classic house-robber problem with one added constraint: since the array is treated as circular for the first/last rule, you solve it twice. Once excluding the last element, once excluding the first, and take the max of the two results.
def rob_linear(nums):
prev, curr = 0, 0
for n in nums:
prev, curr = curr, max(curr, prev + n)
return curr
def max_non_adjacent_sum(nums):
if len(nums) == 1:
return nums[0]
return max(rob_linear(nums[:-1]), rob_linear(nums[1:]))The trap most candidates fall into is solving the plain non-adjacent-sum problem and forgetting the circular constraint entirely. Naming that constraint out loud before writing code is worth more than jumping straight to the DP recurrence.
Sort arrivals and departures into two separate arrays, then walk them with two pointers, incrementing a counter on an arrival and decrementing on a departure, tracking the running maximum. It's structurally the same problem as "minimum meeting rooms required" and comes up under both names in candidate reports.
def min_chairs(arrivals, departures):
arrivals.sort()
departures.sort()
i = j = chairs = max_chairs = 0
while i < len(arrivals):
if arrivals[i] <= departures[j]:
chairs += 1
max_chairs = max(max_chairs, chairs)
i += 1
else:
chairs -= 1
j += 1
return max_chairsReverse each group of k nodes iteratively, then reconnect the reversed group to the tail of the previous group and the head of the next group. The part candidates get wrong most often is the leftover group at the end that has fewer than k nodes: the problem usually asks you to leave that final partial group unreversed, which means you have to count ahead before reversing to know whether a full group even exists.
def reverse_k_group(head, k):
node, count = head, 0
while node and count < k:
node = node.next
count += 1
if count < k:
return head
prev, curr = None, head
for _ in range(k):
nxt = curr.next
curr.next = prev
prev, curr = curr, nxt
head.next = reverse_k_group(curr, k)
return prevRecurse down both subtrees. If a node itself matches either target, return it. If both left and right recursive calls return something non-null, the current node is the LCA, because that means one target lives on each side. If only one side returns non-null, propagate that result upward.
def lowest_common_ancestor(root, p, q):
if not root or root == p or root == q:
return root
left = lowest_common_ancestor(root.left, p, q)
right = lowest_common_ancestor(root.right, p, q)
if left and right:
return root
return left or rightWorth flagging if it's a BST specifically, since that version is a one-liner comparing values against the root instead of a full traversal, and interviewers sometimes ask which version you'd write given the extra structure.
Sort by start time, then walk through once, merging the current interval into the last one in the result list whenever its start is less than or equal to that last interval's end.
def merge_intervals(intervals):
intervals.sort(key=lambda x: x[0])
merged = [intervals[0]]
for start, end in intervals[1:]:
if start <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], end)
else:
merged.append([start, end])
return mergedCount frequencies with a hash map, then either sort by count and take the top k, or use a min-heap of size k for a better bound when k is much smaller than n. Bucket sort by frequency gets you true O(n) if the follow-up pushes for it, since frequency can never exceed array length, giving you a bounded number of buckets to walk.
import heapq
from collections import Counter
def top_k_frequent(nums, k):
counts = Counter(nums)
return heapq.nlargest(k, counts.keys(), key=counts.get)This is cycle detection in a directed graph, dressed up as a scheduling problem. Build an adjacency list from prerequisites, then run a topological sort with Kahn's algorithm: repeatedly remove nodes with in-degree zero. If every node gets removed by the end, there's no cycle and the courses are finishable; if some nodes are left stuck with nonzero in-degree, there's a dependency cycle.
from collections import deque
def can_finish(num_courses, prerequisites):
graph = [[] for _ in range(num_courses)]
indegree = [0] * num_courses
for course, prereq in prerequisites:
graph[prereq].append(course)
indegree[course] += 1
queue = deque([c for c in range(num_courses) if indegree[c] == 0])
visited = 0
while queue:
node = queue.popleft()
visited += 1
for nxt in graph[node]:
indegree[nxt] -= 1
if indegree[nxt] == 0:
queue.append(nxt)
return visited == num_coursesEach node holds a dictionary of child characters and a flag marking whether a complete word ends there. Insert walks character by character, creating nodes as needed. Prefix search walks the same way and returns whether the path exists, regardless of whether a word technically ends at that exact node.
class TrieNode:
def __init__(self):
self.children = {}
self.is_word = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
node = self.root
for ch in word:
node = node.children.setdefault(ch, TrieNode())
node.is_word = True
def starts_with(self, prefix):
node = self.root
for ch in prefix:
if ch not in node.children:
return False
node = node.children[ch]
return TrueCheckout needs consistency over availability. A shopper who gets charged and then sees an order failure because two replicas disagreed on inventory is a worse failure mode than checkout being briefly slower or occasionally unavailable during a network partition.
Product browsing is the opposite. A stale "in stock" badge that's a few seconds behind reality is a minor annoyance, but a browse page returning an error because one cache replica lagged is a real conversion hit multiplied across millions of page views. That's the reasoning behind treating these as genuinely different systems with different consistency guarantees rather than one uniform policy applied everywhere.
Single responsibility means the class that validates a payment method isn't the same class that charges a card, isn't the same class that logs the transaction for audit purposes. Each of those is a reason to change the code independently, so each gets its own class. Open-closed means adding a new payment method, a new wallet provider, say, means adding a new class that implements a shared PaymentMethod interface, not modifying an existing `switch` statement that already handles five other payment types.
The failure mode I've seen in real codebases is a `PaymentProcessor` class that grew a new `else if` branch for every payment provider added over three years, until nobody could touch it without risking every other provider breaking. That's the concrete cost these principles are meant to prevent, not abstract textbook value.
Double-checked locking is the classic answer: check if the instance is null without a lock first, and only enter the synchronized block if it actually looks uninitialized. The `volatile` keyword on the instance field isn't optional here, it prevents instruction reordering that could otherwise let another thread see a partially constructed object.
public class ConfigManager {
private static volatile ConfigManager instance;
private ConfigManager() {}
public static ConfigManager getInstance() {
if (instance == null) {
synchronized (ConfigManager.class) {
if (instance == null) {
instance = new ConfigManager();
}
}
}
return instance;
}
}An initialization-on-demand holder class sidesteps this entirely by relying on the JVM's own class-loading guarantees instead of hand-rolled locking, and it's worth mentioning as the cleaner alternative even if double-checked locking is what gets asked for directly.
A process has its own isolated memory space; a thread shares memory with every other thread in the same process. That shared memory is exactly why threads are cheaper to create and communicate faster, and exactly why they introduce race conditions that a separate process never could, since two threads can read and write the same variable at the same instant.
At high request volume, the choice between spinning up more processes versus more threads (or an async event loop) is a real capacity-planning decision, not trivia. More processes means more memory overhead and slower context switches between them; more threads means cheaper concurrency but a much bigger surface area for subtle bugs if shared state isn't guarded carefully.
Dependency injection means a class declares what it needs through its constructor or fields, and a framework, Spring's container in this case, wires in the actual implementation at runtime instead of the class instantiating its own dependencies directly. A `CheckoutService` that takes a `PaymentGateway` as a constructor argument doesn't hardcode which payment provider it talks to.
@Service
public class CheckoutService {
private final PaymentGateway paymentGateway;
@Autowired
public CheckoutService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
}The real payoff at scale is testability and swappability. Unit tests can inject a mock `PaymentGateway` without spinning up a real payment provider, and swapping providers in production, or running two side by side for a migration, becomes a configuration change instead of a code change across every place that touches payments.
A closure is a function that retains access to variables from the scope it was defined in, even after that outer scope has finished executing. A counter function that returns an inner increment function is the cleanest real example, since the inner function keeps a private reference to a count variable that nothing outside can touch directly.
function makeCounter() {
let count = 0;
return function () {
count += 1;
return count;
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2On the event loop: JavaScript runs on a single thread, so an async callback, a `fetch` response or a `setTimeout`, doesn't run immediately even when it resolves instantly. It gets queued and only runs once the current call stack is completely empty, which is why a `setTimeout(fn, 0)` still runs after every synchronous line of code that comes after it in the source, not before.
Concrete details carry this one: which time zones, how you handled the handoff between them, what async documentation you wrote so a teammate ten hours away wasn't blocked waiting for a live meeting. A specific example, "our India team picked up the ticket at their morning standup because I'd left a written decision log instead of just a Slack thread," lands better than a general statement about being a good communicator.
The honest version of this story usually includes some frustration, work that got thrown out, a deadline that moved, a stakeholder who changed their mind. Naming that friction instead of pretending you were unbothered by it is what makes the answer credible. What matters more than the emotional reaction is the concrete action you took next: what you salvaged from the old direction, what you cut, and how quickly the team got re-aligned on the new plan.
The instinct to badmouth the other person is the single easiest way to lose points on this question. A strong answer describes the actual friction concretely, one person wanted daily status updates and the other found that intrusive, say, without turning it into a character attack, and focuses on the specific adjustment that resolved it rather than a vague "we talked it out and things got better."
A real number matters here, conversion lift, latency reduction, cost saved, error rate dropped, and it should be a number you can actually defend if pressed on how it was measured. Vague claims like "significantly improved performance" without a before-and-after figure read as weaker than a modest, specific number you clearly measured yourself.
This question is really checking whether you think about the business side of the work at all, or only the code. A grounded answer references something concrete, the shift toward unified omnichannel inventory, or the operational cost pressure of same-day delivery, rather than a vague gesture at "AI is changing everything." Tying it back to a specific way it would change your own day-to-day priorities is what makes the answer land instead of sounding like a trend-report summary.
The reasoning matters more than the specific feature you land on. Start from a real friction point you've noticed or can reasonably infer, browsing feels slow, in-store pickup status is unclear, then talk through how you'd validate that it's actually a widespread problem before committing engineering time to it, and what metric would tell you the fix worked.
Naming a tradeoff you're aware of, this improves conversion for pickup shoppers but adds complexity to the order-status backend, shows more judgment than presenting an idea as if it has no downside at all.
A concrete prioritization framework, reach times impact divided by effort, or a simpler cost-of-delay comparison, is useful, but reciting a framework by name isn't the actual answer. The stronger response walks through how you'd get each stakeholder's underlying goal on the table, since "marketing wants feature A" and "marketing wants to hit their Q3 engagement number" are different conversations that can lead to different resolutions once the real goal is visible.
Hard questions
6Preorder traversal with explicit null markers works cleanly and reconstructs unambiguously without needing an inorder traversal alongside it. Encode each node as it's visited, writing a sentinel for every missing child, then decode by consuming the same sequence in the same order and recursively building left and right subtrees.
def serialize(root):
vals = []
def dfs(node):
if not node:
vals.append('#')
return
vals.append(str(node.val))
dfs(node.left)
dfs(node.right)
dfs(root)
return ','.join(vals)
def deserialize(data):
vals = iter(data.split(','))
def build():
val = next(vals)
if val == '#':
return None
node = TreeNode(int(val))
node.left = build()
node.right = build()
return node
return build()Interviewers usually follow up asking whether this works for a general (not just binary) tree, and the honest answer is yes with a small change: store the child count instead of relying on left/right slots being fixed.
Word ladder is breadth-first search on an implicit graph where each word is a node and an edge exists between two words that differ by exactly one letter. BFS guarantees the first time you reach the end word, you've found the shortest path, since BFS explores level by level.
from collections import deque
def ladder_length(begin_word, end_word, word_list):
words = set(word_list)
if end_word not in words:
return 0
queue = deque([(begin_word, 1)])
while queue:
word, steps = queue.popleft()
if word == end_word:
return steps
for i in range(len(word)):
for c in "abcdefghijklmnopqrstuvwxyz":
candidate = word[:i] + c + word[i+1:]
if candidate in words:
words.remove(candidate)
queue.append((candidate, steps + 1))
return 0Removing a word from the set the moment it's queued, rather than after it's dequeued, is what keeps this from timing out on longer word lists. Skipping that step is the most common reason this solution passes small test cases and fails on the larger hidden ones.
Binary search on the smaller array to find a partition point such that everything to the left of the combined partition is less than or equal to everything on the right. Once that partition is correct, the median comes directly from the four boundary elements, without ever building a merged array.
def find_median_sorted_arrays(a, b):
if len(a) > len(b):
a, b = b, a
m, n = len(a), len(b)
lo, hi = 0, m
while lo <= hi:
i = (lo + hi) // 2
j = (m + n + 1) // 2 - i
a_left = a[i-1] if i > 0 else float('-inf')
a_right = a[i] if i < m else float('inf')
b_left = b[j-1] if j > 0 else float('-inf')
b_right = b[j] if j < n else float('inf')
if a_left <= b_right and b_left <= a_right:
if (m + n) % 2 == 0:
return (max(a_left, b_left) + min(a_right, b_right)) / 2
return max(a_left, b_left)
elif a_left > b_right:
hi = i - 1
else:
lo = i + 1Most candidates get the intuition right and then fumble the index math for the odd-length case. Walking through a tiny example on paper before coding, arrays of size 3 and 2, catches the off-by-one before it costs you the whole answer.
Producer threads add items to a shared queue, consumer threads remove them, and the queue has a fixed capacity, so producers must block when it's full and consumers must block when it's empty. Two condition variables, one signaling "not full" and one signaling "not empty," alongside a mutex guarding the queue itself, is the classic solution. Java's BlockingQueue or Python's queue.Queue implement exactly this at the implementation level, so in an interview it's fair to reference the built-in and then explain what it's doing internally.
class BoundedQueue<T> {
private final Queue<T> queue = new LinkedList<>();
private final int capacity;
public BoundedQueue(int capacity) { this.capacity = capacity; }
public synchronized void produce(T item) throws InterruptedException {
while (queue.size() == capacity) wait();
queue.add(item);
notifyAll();
}
public synchronized T consume() throws InterruptedException {
while (queue.isEmpty()) wait();
T item = queue.poll();
notifyAll();
return item;
}
}This is one of the questions candidates specifically flag as tied to the "concurrency and scalability" theme in Walmart's coding loop, not just generic DSA (Glassdoor).
The strongest answers to this one admit the uncertainty honestly rather than pretending you had a clear picture the whole time. Walk through what information you did have, what assumption you made explicitly to move forward anyway, and how you validated or corrected that assumption once more data came in. Interviewers are listening for whether you froze waiting for certainty that was never going to arrive, or made a reasoned call and adjusted course.
Own the outcome honestly, including if it went sideways. A decision that worked out is a fine story, but a decision that didn't, paired with what you learned and changed about how you make similar calls afterward, often demonstrates more judgment than a clean success story would. Vague hedging about "it worked out well overall" without specifics is the version that reads as rehearsed rather than real.
Real-time scenario questions
9A hash map gives O(1) lookup, and a doubly linked list gives O(1) removal and re-insertion at the front without shifting anything. The map stores keys pointing to list nodes, and every access moves that node to the front; when capacity is exceeded, the node at the back gets evicted.
class Node:
def __init__(self, key, val):
self.key, self.val = key, val
self.prev = self.next = None
class LRUCache:
def __init__(self, capacity):
self.cap = capacity
self.map = {}
self.head = Node(0, 0)
self.tail = Node(0, 0)
self.head.next = self.tail
self.tail.prev = self.head
def _remove(self, node):
node.prev.next, node.next.prev = node.next, node.prev
def _add_front(self, node):
node.next = self.head.next
node.prev = self.head
self.head.next.prev = node
self.head.next = node
def get(self, key):
if key not in self.map:
return -1
node = self.map[key]
self._remove(node)
self._add_front(node)
return node.val
def put(self, key, val):
if key in self.map:
self._remove(self.map[key])
node = Node(key, val)
self.map[key] = node
self._add_front(node)
if len(self.map) > self.cap:
lru = self.tail.prev
self._remove(lru)
del self.map[lru.key]An event-driven design decouples this cleanly: an order-state-change publishes an event to a message bus, and separate notification workers subscribe based on event type and stakeholder, rather than the order service knowing how to format an SMS, a push notification, and a seller-dashboard update all itself.
Order Service -> Event Bus (order.shipped, order.delayed, order.delivered)
|-> Customer notification worker (push, email, SMS)
|-> Seller notification worker (dashboard update, webhook)
|-> Delivery partner worker (route update)Adding a new channel later, WhatsApp notifications, say, just means a new subscriber on the existing event types, no changes to the order service itself. That extensibility is usually the actual thing being tested here, more than the notification delivery mechanics.
Token bucket is the algorithm I'd default to: each client gets a bucket that refills at a fixed rate, and every request consumes a token, getting rejected once the bucket is empty. It's simple, allows short bursts up to the bucket size, and is easy to reason about compared to sliding-window counters.
class TokenBucket:
def __init__(self, capacity, refill_rate):
self.capacity = capacity
self.tokens = capacity
self.refill_rate = refill_rate
self.last_refill = time.time()
def allow_request(self):
now = time.time()
elapsed = now - self.last_refill
self.tokens = min(self.capacity, self.tokens + elapsed * self.refill_rate)
self.last_refill = now
if self.tokens >= 1:
self.tokens -= 1
return True
return FalseAt a distributed scale you'd move the bucket state into Redis with an atomic script rather than keeping it in a single process's memory, since every gateway instance needs to see the same count for a given client.
Consistent hashing spreads keys across cache nodes so adding or removing a node only reshuffles a small fraction of keys instead of the whole cache. A stampede happens when a popular key expires and thousands of requests hit the database simultaneously trying to repopulate it.
The fix I'd reach for is a short lock or "in-flight" marker per key: the first request that misses the cache takes responsibility for refetching and repopulating, while other requests for that same key either wait briefly or serve a slightly stale value instead of all hammering the database at once. Setting a randomized jitter on TTLs also spreads out expirations so they don't all land at the same second in the first place.
A strategy pattern fits naturally here: define a DiscountStrategy interface with an apply(cart) method, and implement one concrete class per discount type, percentage off, buy-one-get-one, flat amount off a category. The cart holds a list of active strategies and applies each in turn, rather than branching on a discount-type enum inside the cart's own pricing logic.
interface DiscountStrategy {
double apply(Cart cart);
}
class PercentageDiscount implements DiscountStrategy {
private final double percent;
PercentageDiscount(double percent) { this.percent = percent; }
public double apply(Cart cart) {
return cart.getSubtotal() * (percent / 100);
}
}New discount types become new classes instead of new branches in existing code, which is the actual thing being tested, whether you reach for open-closed principle on your own or need it prompted.
Model requests as two kinds: an external call from a floor (up or down button) and an internal request from inside a car (a floor button pressed by a rider). An `Elevator` maintains its current floor, direction, and a queue of pending stops, and a `Dispatcher` decides which elevator answers a new external call, typically the closest one already moving in the right direction, to minimize total wait time across the building.
The interesting edge case interviewers push on: what happens when a car is moving up, passes floor 5, and a new call comes in from floor 3 wanting to go down. The right answer is that car shouldn't take that call since it's moving the wrong direction relative to the request, and the dispatcher needs that directional logic explicit, not just "nearest elevator."
The hard part isn't storing a count per SKU per store, it's reservation semantics across channels that all draw from the same physical stock. A checkout event in-store needs to decrement immediately and consistently. An e-commerce "add to cart" is closer to a soft hold that expires if checkout doesn't complete, since holding real inventory hostage for every abandoned cart would tank actual availability.
I'd split this into a strongly-consistent path for anything that actually commits stock, in-store POS decrements and completed online checkouts, and an eventually-consistent path for browse-time availability shown to shoppers, with an explicit staleness bound the business is willing to tolerate. Physical counts drift from what the system believes no matter how careful the design is, so a reconciliation job against cycle counts isn't an afterthought, it's a required piece of the system, not a nice-to-have.
Baseline traffic on a normal day might be 20 to 50 times lower than the doorbuster spike at midnight, and that spike is on a known calendar, which changes the design conversation from "how do we auto-scale reactively" to "how do we pre-scale for a date we already know." Pre-provisioning capacity ahead of the event, rather than relying purely on autoscaling that reacts a few minutes too late, is the first real decision.
Past that, a queue-based waiting room absorbs burst load honestly instead of pretending the system can handle everyone at once and then timing out silently. I'd keep checkout and payment on a strongly consistent path no matter what, since a double-charge or an oversold item at scale is a much worse outcome than a shopper waiting in a queue for ninety seconds. Recommendations, reviews, and other non-critical parts of the page are exactly what I'd degrade first if load spikes past capacity, since a slow recommendation carousel costs nothing compared to a failed checkout.
The core risk is two promotions stacking when the business rules say only one should apply, or the same promotion applying twice across a retry. I'd model each promotion as a rule with explicit precedence and mutual-exclusion groups, evaluated once per cart in a deterministic order, and I'd make the whole evaluation idempotent by keying it to a cart-version or checkout-session ID so a retried request produces the same discount, not a second one stacked on top.
Pricing also needs an audit trail. Every discount applied should be logged with which rule fired and why, because "why did this customer get charged $4 less than the sticker price" is a support and finance question that comes up constantly at retail scale, and reconstructing it after the fact without a log is close to impossible.
How to prepare for a Walmart interview
Start with the online assessment's actual constraints, not generic LeetCode grinding. Candidates report a strict per-question timer on the MCQ section and a locked, no-internet coding environment for the OA itself, so practicing under a real clock, not an untimed problem set, matters more here than for a company that lets you take your time. Prioritize trees, graphs, dynamic programming, and one or two concurrency problems specifically, since those show up disproportionately in candidate reports compared to pure array manipulation.
For system design, skip the generic "design Twitter" prep and practice retail-shaped problems instead: an inventory system with two channels, a checkout flow with a known traffic spike, a notification fan-out. If you're interviewing for a role near Walmart's cloud or platform teams, cloud infrastructure fundamentals and basic retail domain knowledge give you a real edge over a candidate who's only ever designed consumer-social-app systems.
For the behavioral and hiring-manager rounds, prepare three or four STAR stories in advance that each demonstrate a different value, ownership under pressure, resolving a disagreement, learning something fast, and be ready for "why Walmart" to come up in more than one round, since candidate reports mention it recurring across the hiring-manager conversation and sometimes the recruiter screen too.
Get the reps in before the real thing
Reciting a discriminant property or a two-pointer trick in your head is not the same as defending it out loud once an interviewer changes a constraint mid-answer. LastRoundAI's mock interview mode runs live coding and system-design rounds with real-time follow-up questions in your browser, and the free plan includes 15 credits a month that reset monthly instead of piling up unused. Starter is $19/mo if a handful of sessions isn't enough runway before a real Walmart loop.
Once your answers hold up under a follow-up, the slower part is usually just getting in front of enough roles that actually run this kind of loop. 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.
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 Walmart ask system design at every level?
From mid-level upward, almost always, and it carries increasing weight as you go up. Junior loops may include a lighter version focused on structuring a feature rather than designing a distributed system.
What behavioural signals does Walmart look for?
Concrete ownership stories with a real outcome. Vague team-level answers score poorly; interviewers are listening for what you specifically did, what it cost, and what you learned when it went wrong.
How long is the Walmart hiring process?
Often three to eight weeks end to end, with the gap between onsite and decision being the slowest part. Team matching, where it applies, can add further time and is not a reflection on your performance.
How many interview rounds does Walmart have?
Usually a recruiter screen, a technical phone screen, then an onsite loop of four to five rounds covering coding, system design and behavioural. The exact count shifts by level and team, and some loops add a domain-specific round, so ask your recruiter for the actual schedule.
How hard is the Walmart interview?
Hard, but the difficulty is more about depth of follow-up than exotic questions. Interviewers tend to take a reasonable problem and keep pushing on trade-offs, edge cases and what you would change at ten times the load. Preparing to be interrogated on an answer matters more than memorising more answers.
- Walmart Software Engineer Interview Questions
- GeeksforGeeks, Walmart Labs Interview Experience
- GeeksforGeeks, Walmart Interview Experience for SDE 2024 (Off-Campus)
- Blind, Walmart On-Site Interview Questions
- Refer.me, Walmart Labs Data Analyst Behavioral Interview
- Exponent, Walmart Product Manager Interview Guide
