Walmart prep Campus Grad Cybersecurity
Code and CS8,137 words, about 41 min

Programming, DSA and CS

Walmart Campus Grad — Cybersecurity Intern Prep Covers: language fluency, DSA patterns, OOP live coding, OS/DBMS/CN fundamentals, secure coding, and DevOps basics. Format of the real process (candidate-reported, 2024–2026 drives — varies by drive): OA = ~10–25 MCQs (OS/CN/DBMS/OOP/SQL) + 2–3 DSA problems (easy–medium) on HirePro (22 MCQ/35 min + 2 coding/40 min) / HackerEarth (10 MCQ + 2 coding/90 min) / Sparkplug (25 MCQ + two 90-min rounds) → Technical 1: 1–2 live DSA problems + OOP + SQL → Technical 2: OOP/LLD live code, normalization, SQL vs NoSQL, project deep-dive → HM/HR.


1. Why Walmart Asks This

Walmart Global Tech runs the world's largest retail supply chain: inventory, fulfillment, checkout, fraud detection, and identity systems at massive scale. For a Cybersecurity intern, programming and CS fundamentals matter because:

  1. Security work is code work. You'll write detection rules, audit code for injection flaws, patch services, and script automation. The JD lists Python/C/C++/Java plus Go (TCP/Gin/sqlc) — you must reason about code in all of them.
  2. The OA is a filter for correctness under time pressure. Typically 10–25 MCQs in ~35 minutes (~60–90 seconds per question — exact format varies by drive, see above) — you either know OS/DBMS/OOP cold or you don't. The 2–3 coding problems are LeetCode easy–medium; fully-passing solutions beat clever partial ones.
  3. Live rounds test how you think. Reported repeatedly: interviewers value narration (brute → optimize), complexity analysis, dry runs, and edge-case rigor over raw speed. Silent coding loses the round even with correct code.
  4. OOP + DBMS are the security baseline. Parameterized SQL, normalization (data integrity), and the four pillars (encapsulation = least privilege in code) are how you defend a retail platform.
  5. Scale awareness. Walmart-sized data means indexing, caching, heaps for Top-K, BFS/DFS on huge grids (warehouse routing, fraud graphs). Mentioning this distinguishes you from toy-version candidates.

2. Concepts + Examples (Full Checklist)

2.1 Python Fluency

Concept What to know Snippet
Mutability list/dict/set mutable; tuple/str/frozenset immutable a = (1,2); a[0] = 3 # TypeError
Slicing s[start:stop:step], reversal s[::-1] s = "abc"; s[::-1] # "cba"
Comprehensions list/dict/set + generator expressions sq = [x*x for x in range(5) if x % 2 == 0]
defaultdict/Counter O(1) frequency counting Counter("abracadabra") → {'a':5,...}
bisect binary search on sorted lists (search O(log n), insert O(n) — shifts) bisect.insort(a, x)
heapq min-heap; negate for max-heap heapq.nlargest(k, nums)
Exceptions try/except/finally, custom exceptions raise ValueError on bad input
== vs is equality vs identity [] == [] # True; [] is [] # False
GIL one thread executes bytecode at a time; use multiprocessing for CPU-bound work (default build; 3.13+ optional free-threaded build, PEP 703) —
Typing hints don't enforce; mypy does def f(x: int) -> str:
File I/O with open() + json/csv; never leave handles open with open('a.log') as f: data = f.read()
requests timeout + raise_for_status(); never verify=False requests.get(url, timeout=5, verify=True)

Why this table is a list of traps. Python lets you express the same operation several ways, and OAs test the version with a hidden aliasing or memory cost; the worked example below covers the most common failure.

Worked example — aliasing vs copying.

a = [1, 2, 3]
b = a            # b is another name for the SAME list object
b.append(4)
print(a)         # [1, 2, 3, 4]  -> mutation is visible through both names

c = a[:]         # shallow copy: new list, same element objects
c.append(5)
print(a)         # [1, 2, 3, 4]  -> unchanged

# (mutable default: def collect(x, seen=[]) shares one list across all calls)

= never copies a container, so copy explicitly with a[:], list(a), a.copy(), or copy.deepcopy(a) for nesting. The mutable default (seen=[]) is created once at definition time and shared by every call; fix it with seen=None and if seen is None: seen = []. Tuples and strings are immutable, which is why a = (1, 2); a[0] = 3 raises TypeError and why they can be dictionary keys.

Counter in one line: it is a dict subclass that returns 0 for a missing key, so count[x] += 1 needs no membership test; building it is O(n), and most_common(k) uses a size-k heap selection rather than a full sort.

Python OOP (6 lines):

from dataclasses import dataclass
@dataclass
class User:
    name: str; uid: int
    def is_admin(self): return self.uid == 0
class Admin(User):
    def is_admin(self): return True  # inheritance + override

2.2 C / C++ / Java / Go Basics — Value vs Reference, Pointers

Language Passing semantics Memory Key gotcha
C always by value; */& for pointers manual malloc/free dangling pointers, memory leaks, buffer overflow (security!)
C++ by value; &/* for references/pointers; move semantics new/delete, smart pointers pass-by-ref void f(int &x) modifies caller's variable
Java always pass-by-value — the value of an object reference is copied GC heap reassigning a parameter does NOT affect caller; mutating the object DOES
Python pass-by-object-reference ("call by assignment") ref-counted GC def f(x): x = 5 no effect outside; def f(l): l.append(1) mutates
Go by value; pointers *T, &x; slices/maps are reference-like headers GC passing a slice copies the header, not the backing array
#include <stdio.h>
/* C: by value vs pointer */
void byval(int x)  { x = 10; }   /* caller unchanged */
void byptr(int *x) { *x = 10; }  /* caller changed */
int main(void) { int a = 1; byval(a); byptr(&a); printf("%d\n", a); return 0; }  /* a == 10 */
// Java: reference copied BY VALUE (methods live in a class)
class ParamDemo {
    static void rebind(StringBuilder s) { s = new StringBuilder("new"); }  // no effect outside
    static void mutate(StringBuilder s) { s.append("!"); }                 // effect outside
}

Go vs others: compiled + statically typed with goroutines (cheap concurrency), no inheritance (composition + interfaces), defer for cleanup — a great fit for security tooling (your resume: Go TCP/Gin/sqlc).

What "passing semantics" actually means. When a function is called, the language decides what the callee receives: a copy of a value (C, C++, Java, Go) or an alias to the caller's variable (C++ references). Copying a primitive is free, but copying a large struct is not, which is why C++ passes const std::string&. Java confuses people because the copied value can itself be a reference: the callee gets a copy of the arrow, so it can reach the same object but cannot redirect the caller's variable.

Trace the C snippet above. a starts at 1. byval(a) copies the value 1 into x, and x = 10 changes only that copy, so a is still 1. byptr(&a) copies the address of a into x; *x = 10 writes through that address into a's storage, so a becomes 10 and the program prints 10. The mental model: pass by value copies the arrow, pass by pointer tells the callee where the arrow points.

Trace the Java snippet. rebind receives a copy of the caller's reference, so s = new StringBuilder("new") only reassigns the copy and the caller keeps the original builder. mutate receives a copy too, but s.append("!") sends a message to the object the copy points at, so the caller observes the change. This asymmetry is the single most common Java interview trap.

Why Go slices surprise people. A slice is a three-word header (pointer to the backing array, length, capacity). Passing a slice copies the header, so append inside the callee may write into the caller's array — but past capacity it allocates a new array and the caller's header still points at the old one, so functions that grow a slice return it (s = append(s, x)).

2.3 OOP — Four Pillars + Live Code

Pillar Definition Java/C++ flavor Security angle
Encapsulation hide state; expose behavior private fields + getters/setters validation happens in ONE place (setter)
Abstraction hide implementation abstract class, interface callers can't misuse internals
Inheritance is-a reuse extends, : public Base careful: fragile base class
Polymorphism one interface, many forms overriding (runtime), overloading (compile-time) plugins/filters without switch-cases

Virtual functions + binding + abstract classes: - Static binding (compile-time): overloading, static methods, final methods — resolved by the declared type at compile time. - Dynamic binding (runtime): overridden methods via a base-class pointer/reference — the vtable (C++) or virtual method table (Java) dispatches on the actual object type. - C++: virtual keyword enables dynamic dispatch; pure virtual virtual double area() const = 0; makes a class abstract. Always a virtual destructor in a base class (else UB on delete-via-base-pointer). - Java: all non-private, non-static, non-final instance methods are virtual by default (dynamic binding; private/static use static binding — static methods are hidden, not overridden); abstract methods have no body; interface = pure abstraction (Java 8+ allows default methods). - Abstract class vs interface: abstract class = shared state + partial implementation ("is-a" base); interface = capability contract ("can-do"), multiple allowed in Java/C++.

Square/LSP trap (Walmart live-code favorite): don't class Square extends Rectangle with independent set_w/set_h — it breaks Liskov Substitution (a Square can't honor set_w(4); set_h(5)). Prefer both extend Shape. SOLID in one line: S-single responsibility, O-open/closed (extend, don't edit), L-subtypes substitutable, I-interface segregation, D-depend on abstractions. Diamond: Java default-method clash → overriding class must resolve; C++ diamond → virtual inheritance.

How dynamic binding is implemented (the part interviewers probe). Every class with virtual methods gets a table of function pointers: the vtable in C++, the method table in the JVM. Each object of such a class carries a hidden pointer to its class's table. A call like shape.area() compiles to "load the table pointer from the object, index the slot reserved for area, call that address." An override replaces the pointer in the subclass's table, so one call site reaches different code depending on the object's actual type; overloading instead resolves at compile time, before any object exists.

Worked example — the virtual destructor leak. Shape* s = new Circle(2); delete s; with a non-virtual ~Shape() makes the compiler emit a direct call to Shape::~Shape; the Circle part of the object is never destroyed and anything it owns leaks. Deleting a base pointer whose static and dynamic types differ is undefined behavior. With virtual ~Shape() = default; the call goes through the vtable: Circle::~Circle runs first, then Shape::~Shape. Rule: any class intended for polymorphic deletion needs a virtual destructor.

Worked example — why Square extends Rectangle breaks LSP. A test written against Rectangle might assert that after set_w(4); set_h(5) the area is 20. If Square overrides both setters to keep the sides equal, the area becomes 25 and the test fails even though it did nothing wrong. Substitutability means a client must not need to know which subclass it holds. The clean design is a common Shape abstraction with area() and separate Rectangle and Square implementations; if shared quadrilateral behavior is needed, compose it instead of inheriting it.

2.4 DSA Patterns (Master List)

Pattern When to reach for it Complexity Walmart-reported problems
Arrays/Strings prefix sums, difference array for range updates, in-place scans O(n) count powers of 2 + sum; max odd number in string; right-shift subarray queries (difference array / index transform, O(1) per update)
Hashing frequency, seen-before, grouping O(n) avg max-occurring number; most visited page/country
Two pointers sorted pairs, palindromes, partitions O(n) longest palindromic substring; container-with-most-water style
Sliding window subarray/substring with constraint (non-negative only; with negatives use prefix sums + ordered set, O(n log n)) O(n) max sum < k (modified Kadane, non-negative); balanced windows
Intervals merging, overlap, scheduling O(n log n) merge intervals; meeting rooms
Stack/Queue matching, next-greater, monotonic O(n) valid parentheses; max-rectangle in binary matrix
Heap / Top-K K largest, running stream, merge-k O(n log k) first 5 largest in a running stream; Top-K frequent
BFS shortest path in unweighted grid/graph O(V+E) shortest path in a grid; number of islands
DFS connectivity, backtracking, permutations O(V+E) word search in 2D grid; string permutations
Union-Find (DSU) connectivity, components, offline reverse processing O(α(n)) ≈ O(1) unreachable pairs after edge removal (reverse DSU)
Dijkstra weighted shortest path (non-negative weights) O((V+E) log V) train route with arrival/departure windows
Trees recursion, BST checks, traversals, LCA O(n) validate BST; spiral/diagonal traversal; burning tree; min distance between 2 nodes (depth[u]+depth[v]-2*depth[lca], or 2×BFS)
Binary search sorted search, boundary, rotated, "minimize the max" O(log n) bitonic array search; search in row-col sorted matrix
Dynamic programming overlapping subproblems, choices O(n)–O(n²) house robber (no-adjacent, circular); subset/ways-sum

2.4.1 Deriving Big-O on one example

Big-O is not a label to memorize; it is a count of how many operations run as the input grows, with constants and lower-order terms dropped. Take the brute-force Two Sum:

def two_sum_brute(nums, target):
    for i in range(len(nums)):              # n iterations
        for j in range(i + 1, len(nums)):   # n-1, n-2, ..., 1
            if nums[i] + nums[j] == target:
                return [i, j]
    return []

The inner loop runs n−1 + n−2 + … + 1 = n(n−1)/2 = n²/2 − n/2 times, so the work is O(n²). For n = 10⁵ that is about 5×10⁹ comparisons, beyond the ~10⁸ simple operations a judge typically allows per second, so a correct solution still fails on time. The hash-map version scans once and checks, for each x, whether target − x was already seen: O(n) time, O(n) space. State the trade aloud: O(n) memory buys a factor of n in time. Trace on nums = [2, 7, 11, 15], target = 9: insert 2 → {2: 0}; see 7, complement 2 is present → return [0, 1]. Duplicates work because the check happens before the insert: [3, 3] with target 6 returns [0, 1] and never reuses one element.

2.4.2 Two-pointer worked trace (Container With Most Water)

What it is: a scan from both ends of a sequence that moves only the pointer that can still improve the answer. Why it appears: it converts O(n²) pair scans into O(n) and tests whether you can justify a greedy move rather than just describe code. How it works: start L at the left edge and R at the right edge; the area is (R − L) × min(h[L], h[R]). Record it, then move the pointer at the shorter line inward, because any rectangle that keeps that line is height-bounded by it and strictly narrower than the one just recorded.

Trace on h = [1, 8, 6, 2, 5, 4, 8, 3, 7]: L=0, R=8 → 8×1 = 8, move L; L=1, R=8 → 7×7 = 49, move R; then L=1, R=7 → 18 and L=1, R=6 → 40, moving the shorter side each time; the remaining steps give 16, 15, 4, 6 before the pointers meet, so the best area is 49. Each iteration moves exactly one pointer: O(n) time, O(1) space. Likely interview question: "Why is it safe to move only the shorter line?" Model answer: any pair that keeps it is height-bounded by it and narrower than the pair just measured; the taller line can still pair profitably inside, so it stays.

2.4.3 Sliding-window worked trace (Longest Substring Without Repeating Characters)

What it is: a window [l, r] where r always advances and l advances only when the window becomes invalid. Why it appears: it turns a quadratic scan over all substrings into one pass, and most "longest/shortest subarray such that …" questions use it. How it works: store the last-seen index of each character; when r meets a character whose last-seen index is inside the window, move l just past it. The guard last[ch] >= l matters — an index from before the window must not move l backwards.

def longest_unique(s):
    last, l, best = {}, 0, 0
    for r, ch in enumerate(s):
        if ch in last and last[ch] >= l:
            l = last[ch] + 1        # shrink past the duplicate
        last[ch] = r
        best = max(best, r - l + 1)
    return best

Trace on "abcabcbb": r=0..2 give windows a, ab, abc, best 3. r=3 a (last a = 0 ≥ l = 0) → l=1, window bca, best 3. r=4 b (last b = 1) → l=2, cab. r=5 c (last c = 2) → l=3, abc. r=6 b (last b = 4) → l=5, cb. r=7 b (last b = 6) → l=7, b. Answer 3. Both pointers move forward only, so the loop is O(n) time and O(min(n, alphabet)) space. A while that shrinks instead of a single if handles conjunctions such as at-most-k flips.

Complexity + narrating brute → optimize (the exact script they reward): 1. "n ≤ 10⁵, so I need O(n log n) or better." 2. "Brute force: every pair — O(n²), too slow, but a correct baseline." 3. "Optimization: hash map for O(1) lookups → O(n) time, O(n) space." 4. "Dry-run on [1,2,3]… edge cases: empty input, single element, duplicates, negatives."

Practice problems (do these, narrating out loud): 1. Two Sum · 2. Longest Palindromic Substring · 3. Reverse Linked List · 4. Valid Parentheses · 5. Merge Intervals · 6. Top-K Frequent Elements · 7. Number of Islands (BFS/DFS grid) · 8. Word Search in 2D grid · 9. Binary Search + rotated/bitonic search · 10. House Robber (incl. circular variant) · 11. Spiral matrix traversal · 12. Maximum rectangle of 1s in binary matrix · 13. Second-highest salary (SQL) · 14. Stack via queues / Queue via stacks · 15. Validate BST · 16. Trapping rain water · 17. Longest common subsequence · 18. Topological sort (course schedule) · 19. Min distance between tree nodes (LCA) · 20. Right-shift subarray queries (difference array) · 21. Unreachable pairs after edge removal (reverse DSU) · 22. Intersection of 3 free schedules (sort + 3-pointer sweep) · 23. Queue via two stacks (see §4.7).

2.4.4 Dynamic programming worked example (House Robber)

What it is: decompose a problem into overlapping subproblems and compute each answer once instead of recomputing it. Why it appears: OAs use simple 1-D recurrences to test whether you define a state and a transition. How it works: answer three questions — what does dp[i] mean, how does it come from smaller states, and what are the base cases. Here dp[i] is the best loot using houses 0..i. At house i you skip it (dp[i−1]) or take it plus the best up to i−2 (dp[i−2] + nums[i]), giving dp[i] = max(dp[i−1], dp[i−2] + nums[i]), with dp[0] = nums[0] and an implicit 0 for the empty prefix.

Trace on [2, 7, 9, 3, 1]: dp[0]=2, dp[1]=max(2, 0+7)=7, dp[2]=max(7, 2+9)=11, dp[3]=max(11, 7+3)=11, dp[4]=max(11, 11+1)=12. The answer 12 is houses 0, 2, 4 (2+9+1). Each state uses only the previous two, so two rolling variables suffice: O(n) time, O(1) space. In the circular variant the first and last houses cannot both be taken, so solve nums[0..n−2] and nums[1..n−1] and take the larger result.

2.5 Operating Systems (OA MCQ favorites)

Topic Must-know answer
Process vs Thread Process = independent address space, heavy context switch; Thread = shared address space within a process, lighter. Thread types: user-level vs kernel-level.
Paging logical address = (page #, offset) → page table maps page → frame = physical address. Fixed-size blocks eliminate external fragmentation, cause internal fragmentation.
Segmentation variable-size segments (code/data/stack) = logical view; can combine with paging.
FIFO vs LRU page replacement FIFO replaces oldest page (suffers Belady's anomaly); LRU replaces least-recently-used (good but costly; approximated with clocks). Page fault = page not in memory.
Interrupts hardware/software signal preempting CPU → ISR; types: maskable/non-maskable, traps (software interrupt/syscall).
Deadlock 4 conditions: mutual exclusion, hold-and-wait, no preemption, circular wait. Handling: prevention (break a condition), avoidance (Banker's), detection+recovery, ostrich.
Scheduling FCFS, SJF/SRTF, Round Robin (time quantum), Priority, Multilevel queue. Metrics: waiting time, turnaround, response time, CPU utilization.
Concurrency race condition, critical section, mutex vs semaphore (binary vs counting), producer-consumer.

2.5.1 Process vs thread in a real server

What they are: a process has its own virtual address space, page table, and file-descriptor table; a thread shares all of those with its siblings inside one process. Why it appears: every OS interview starts here, and it decides whether a scanner can hold 10,000 sockets or dies at 1,000. How it works in a server: in a multiprocess model (prefork workers) each request runs in its own process, so a crash or memory-corruption bug kills only that worker and the kernel keeps the others serving. The cost is a new page table on every process switch (a TLB flush) plus IPC for sharing data. In a multithreaded model one address space holds many threads: switching is cheaper, the TLB stays warm, and all threads share the heap and open sockets, so races need mutexes and one unhandled fault or buffer overflow takes down the whole process. Security framing: thread-per-connection maximizes sharing (a race is a vulnerability) and process-per-connection limits the blast radius. Likely question: "Why is a thread switch cheaper?" Model answer: the address space and page table stay the same, so TLB state is not replaced and fewer registers are saved.

2.5.2 Paging address translation with real numbers

With a 32-bit address space and 4 KB pages, 4 KB = 2¹² means the low 12 bits are the offset and the high 20 bits are the page number (up to 2²⁰ ≈ 1,048,576 pages). For virtual address 0x0000A24F, page number = 0xA (10) and offset = 0x24F (591). If page 10 maps to frame 7, the physical address is 7 × 4096 + 591 = 29,263. A flat table of 2²⁰ entries at 4 bytes each is 4 MB per process, which is why real systems use multi-level tables or inverted tables and cache recent translations in the TLB. MCQ shapes: offset bits = log₂(page size); number of pages = address space ÷ page size; physical address = frame × page size + offset.

2.5.3 FIFO vs LRU on a reference string

Take the string 1 2 3 4 1 2 5 1 2 3 4 5 with 3 frames. FIFO evicts in load order: requests 1–3 fill the frames, 4 evicts 1, 1 evicts 2, 2 evicts 3, 5 evicts 4 (all seven faults), 1 and 2 hit, 3 evicts 1, 4 evicts 2, and 5 hits — 9 faults. With 4 frames FIFO faults on requests 1–4, 7, and 8–12: 10 faults, so more frames produced more faults, which is Belady's anomaly. LRU on the same string with 3 frames gives 10 faults. LRU cannot suffer Belady's anomaly because it is a stack algorithm: the set of pages held with k frames is always a subset of the set held with k+1 frames. Fast MCQ method: draw one row per frame and mark each request hit or fault, then count faults.

2.5.4 Scheduling worked numerical

Three processes arrive at time 0 with bursts P1=6, P2=4, P3=2. SJF runs P3, P2, P1: waiting times 0, 2, 6 (average 2.67), turnaround 2, 6, 12 (average 6.67) — the minimum possible average wait, which is why SJF is the benchmark. Round Robin with quantum 2 runs P1 [0,2), P2 [2,4), P3 [4,6) and finishes, P1 [6,8), P2 [8,10) and finishes, P1 [10,12). Waiting = completion − arrival − burst: P1 = 12−0−6 = 6, P2 = 10−0−4 = 6, P3 = 6−0−2 = 4, average 5.33. RR is worse than SJF on average wait here but every process gets the CPU within one quantum, which is what interactive systems need. Turnaround = completion − arrival; response time = first CPU − arrival.

2.6 DBMS (normalization + SQL vs NoSQL + more)

Normalization: - 1NF: atomic values only; no repeating groups (one value per cell, unique rows). - 2NF: 1NF + no partial dependency (every non-key column depends on the whole composite key). - 3NF: 2NF + no transitive dependency (non-key column must not determine another non-key column). - BCNF: for every functional dependency X→Y, X must be a superkey (stricter than 3NF). - Functional dependency (FD): X→Y means rows agreeing on X must agree on Y; find candidate keys via attribute closure (start from LHS set, repeatedly add RHS until fixed point); OA shape: "given FDs, highest normal form?" — check partial (2NF) then transitive (3NF). - Denormalization: intentional redundancy for read performance (Walmart catalog reads) at the cost of anomalies.

SQL vs NoSQL:

Dimension SQL (PostgreSQL/MySQL) NoSQL (DynamoDB/Cassandra/Mongo/Redis)
Schema fixed schema, tables, rows dynamic, documents/key-value/columnar
Relations JOINs, FK constraints denormalized, embedded
Consistency strong (ACID) eventual (BASE) typical
Scaling vertical (with sharding complexity) horizontal by design
Use case orders, payments, auth (integrity) catalog, sessions, caches, logs (scale)

Other DBMS must-knows: - ACID: Atomicity (all-or-nothing), Consistency (constraints hold), Isolation (concurrent transactions don't interfere — levels: read uncommitted → serializable), Durability (committed = survives crash). - Indexes: B+ tree default; speed up reads, slow writes; clustered vs non-clustered; composite index column order matters; hash index for equality only. - JOINs: INNER (matches only), LEFT (all left + matches), RIGHT, FULL OUTER, CROSS (cartesian), SELF. - Anomalies (why normalization matters): insertion, update, deletion anomalies. - Classic SQL queries: second-highest salary (MAX(salary) WHERE salary < (SELECT MAX...) or DENSE_RANK()), latest entry per user (GROUP BY user + MAX(date) or window ROW_NUMBER()).

2.6.1 Functional dependencies, closure, and normal forms

What it is: an FD X → Y means two rows that agree on X must agree on Y. Why it appears: "find the candidate key" and "what is the highest normal form" are standard MCQs, and live-round normalization arguments are just closure calculations. How it works: to test whether X determines an attribute, start with the closure set {X}, scan the FDs, and whenever a left side is contained in the closure add its right side; repeat until nothing changes. Worked example: R(A, B, C, D) with A → B, B → C. Closure of A is {A}, then {A, B} from A → B, then {A, B, C} from B → C; D is not determined, so A alone is not a key. If the declared key is (A, D), then B and C depend on part of the key (A) — a partial dependency — so the table is 1NF but not 2NF, and the fix is a separate table keyed by A. Adding C → D gives the chain A → B → C → D: D is transitively dependent on the key, which is the 3NF violation, and D moves to the table keyed by C.

2.6.2 ACID and isolation on one transfer

Moving 50 from account 1 to account 2 is two statements: debit 1, credit 2. Atomicity means both commit or both roll back, so a crash between them cannot lose money. Consistency means declared constraints (CHECK (balance >= 0), foreign keys) hold after commit. Isolation decides what a concurrent reader sees: read uncommitted can observe the debit before the credit; read committed shows only committed rows but the same row may change between two reads (non-repeatable read); repeatable read fixes that while a re-run range query can still gain rows (phantom read); serializable blocks phantoms and is strictest. Durability means the write-ahead log is flushed before the commit is acknowledged, so the result survives a crash.

2.6.3 JOINs on two tiny tables

customers(id, name) holds (1, Ana), (2, Bo), (3, Cy); orders(id, customer_id, total) holds (10, 1, 50), (11, 3, 20), (12, NULL, 5). An INNER JOIN on orders.customer_id = customers.id returns two rows: (Ana, 50) and (Cy, 20). A LEFT JOIN from customers returns all three customers, with Bo's order columns NULL; filtering that with WHERE o.id IS NULL returns only Bo, the "customers with no orders" answer, and a correlated NOT EXISTS gives the same result.

2.6.4 Injection-safe query patterns across stacks

The Python pattern is in §4.6; the same rule holds in every language because the driver sends the query template and the values on separate channels:

// Java JDBC: placeholders, never string concatenation
String sql = "SELECT id, name FROM users WHERE name = ? AND age >= ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
    ps.setString(1, name);
    ps.setInt(2, minAge);
    try (ResultSet rs = ps.executeQuery()) { /* read rows */ }
}
// Go database/sql: placeholder style depends on the driver
row := db.QueryRow("SELECT id, name FROM users WHERE name = $1 AND age >= $2", name, minAge)

In the sqlc project this is structural: generated functions take typed parameters and emit parameterized SQL, so no handler builds a query from user input. Note that placeholders bind values, not identifiers, so a sort column must come from an allow-list.

2.7 OA MCQ Strategy

  • Topics are GATE-basic: OOP predict-the-output (Java/C++ snippets), OS scheduling/paging numericals, DBMS normalization/SQL output, CN OSI/TCP-UDP, aptitude.
  • Pace: ~60–90 seconds per MCQ — mark and move on; the coding section carries more weight cumulatively.
  • Java output questions: know == vs .equals(), static, this, string immutability, exception flow (try-catch-finally order).
  • Predict-the-output in C/C++: pointer arithmetic, i++ + ++i (UB — say so!), array decay.
  • CN topics (OSI/TCP-UDP/subnetting): see 01-networking.md — this file covers only OA strategy for CN.
  • Predict-the-output drill: String a = "x", b = new String("x"); → a == b false but a.equals(b) true; Integer values in −128..127 compare equal with == (cached), values outside do not; try { return 1; } finally { return 2; } returns 2.

2.8 Secure Coding (Cybersecurity-specific — expect this to come up)

Practice Rule Bad → Good
Input validation validate type, length, range, whitelist chars accept any string → regex whitelist + length cap
Parameterized SQL never concatenate user input into queries "SELECT * FROM u WHERE name='"+n+"'" → prepared statements
Output encoding context-aware encoding (HTML/JS/URL) to stop XSS echo raw input → HTML-encode before render
Authentication bcrypt/argon2 hashing, salt, MFA, session expiry MD5 plaintext → argon2id + per-user salt
Error handling generic messages to user, detail only to logs leak stack traces → log internally, return generic 500
Least privilege minimal permissions for DB users/services root DB account → restricted role
Secrets env/secret manager, never hardcode API_KEY="..." in source → vault injection
Memory safety bounds checking (C/C++), no strcpy → snprintf/std::string (avoid strncpy: may not NUL-terminate) buffer overflow → safe APIs, fuzzing, sanitizers

How to use this in the interview. Name the flaw, the category, then the control: "SQL injection — OWASP A03, injection; fix with a parameterized statement." Validation rejects input at the boundary with an allow-list; encoding happens at the sink and is context-specific (HTML-encode for HTML, URL-encode for URLs).

2.9 Git / Docker / CI + Basic System Design

  • Git: branch → commit → PR → review → merge; rebase vs merge; stash, cherry-pick, conflict resolution; trunk-based vs feature-branch; signed commits for security.
  • Docker: image vs container; Dockerfile layers; volumes; docker-compose; containers share the kernel vs VMs; scan images (Trivy) for CVEs.
  • CI/CD: lint → unit test → SAST/DAST → build → deploy; GitHub Actions/Jenkins; fail the pipeline on high-severity CVEs; artifacts and rollback.
  • Basic system design (fresher-level): load balancer → API gateway → stateless services → cache (Redis) → DB (primary/replica) → queue (Kafka). For security: rate limiting, WAF, TLS termination, audit logging. Keep it simple: "cache hot lookups, shard by store ID."

Why these details matter: each Dockerfile instruction is a cached layer, so copy dependencies before source; containers share the host kernel, so a kernel bug is an escape risk and images should run non-root and be scanned; the CI order runs the cheapest checks first so failures surface in seconds.


3. Q&A (20 questions — 18 core + 2 bonus, spoken answers)

Q1. Difference between a process and a thread? A process has its own address space and is the unit of resource allocation; a thread shares its parent process's memory and is the unit of scheduling. Threads are cheaper to create/switch but share state → races need mutexes. A crashed thread can take down the process; a crashed process is isolated.

Q2. What is virtual memory and paging? Virtual memory gives each process the illusion of a large contiguous address space. Paging splits it into fixed-size pages mapped to physical frames via a page table. Logical address = page number + offset; the MMU translates it (TLB caches translations). Pages not in RAM cause page faults.

Q3. Explain FIFO vs LRU page replacement. FIFO evicts the oldest loaded page — simple, but can evict hot pages and suffers Belady's anomaly (more frames → more faults). LRU evicts the least recently accessed page, approximating locality; exact LRU is expensive, so systems use clock/second-chance approximations.

Q4. What are the four conditions for deadlock and how do you handle it? Mutual exclusion, hold-and-wait, no preemption, circular wait. Prevention breaks one condition (e.g., ordered resource acquisition kills circular wait); avoidance uses Banker's algorithm; detection builds a wait-for graph and recovers by killing a process; most OSes ignore it (ostrich).

Q5. Compare SJF and Round Robin scheduling. SJF gives minimum average waiting time but needs future knowledge and can starve long jobs. Round Robin is fair and responsive (time quantum) with higher context-switch overhead. SRTF = preemptive SJF; priority scheduling risks starvation → aging.

Q6. What are the four OOP pillars? Give a security example for encapsulation. Encapsulation, abstraction, inheritance, polymorphism. Encapsulation: keep a passwordHash field private with a verify() method, so no caller can read or overwrite the hash directly — validation and hashing live in one audited place.

Q7. What's the difference between method overloading and overriding? Binding? Overloading = same name, different parameters, resolved at compile time (static binding). Overriding = subclass redefines a superclass method, resolved at runtime (dynamic binding via vtable). Java instance methods are virtual by default; C++ needs virtual.

Q8. Abstract class vs interface? Abstract class: holds state + partial implementation, single inheritance in Java. Interface: contract (default methods since Java 8), implement many. Use interface for capabilities (Auditable), abstract class for shared base (Account).

Q9. Why is a virtual destructor needed in C++? Deleting a derived object via a base pointer with a non-virtual base destructor runs only the base destructor → leaks/UB. Fix: virtual ~Base() = default;.

Q10. Java: == vs .equals()? == compares primitive values or object references (same object in memory). .equals() compares logical content (if the class overrides it, like String). hashCode contract: equal objects must have equal hash codes.

Q11. Explain pass-by-value vs pass-by-reference with a pointer example. C is always pass-by-value; to mutate the caller's variable you pass its address (int *x) and dereference. C++ adds real references (int &x). Java passes the reference value — rebinding the parameter does nothing outside, but mutating the object does.

Q12. Walk through 1NF → 3NF on an Orders(order_id, customer_name, customer_city, item) table. 1NF: atomic values, no repeating items → split items into OrderItems. 2NF: key is (order_id, item); customer_name/customer_city depend on order_id alone → partial dependency, so move customer columns to Customers. 3NF: customer_city determined by customer_name (transitive) → Customers(customer_id, name, city); orders reference customer_id. BCNF tightens every determinant to a superkey.

Q13. SQL vs NoSQL — when would Walmart use each? SQL for orders, payments, and auth where ACID and JOINs protect integrity. NoSQL for product catalog (documents), session/cache (Redis), and clickstream logs (wide-column) where horizontal scale and flexible schemas matter. A Walmart-scale system uses both (polyglot persistence).

Q14. What is an index and what's the cost? A B+ tree (or hash) structure that turns O(n) scans into O(log n) lookups by keeping sorted pointers to rows. Costs: extra storage, slower INSERT/UPDATE/DELETE, and write amplification. Composite index (store_id, date) serves queries filtering on store_id first — column order matters.

Q15. Explain ACID and isolation levels. Atomicity (transactions all-or-nothing), Consistency (constraints/FKs hold after commit), Isolation (concurrent transactions don't see each other's intermediate state — levels: read uncommitted (dirty reads) → read committed → repeatable read → serializable), Durability (committed data survives crashes via WAL).

Q16. INNER JOIN vs LEFT JOIN? INNER returns only matching rows in both tables. LEFT returns all rows from the left table plus matches (NULLs where no match). "Customers with no orders" = LEFT JOIN + WHERE o.id IS NULL (or NOT EXISTS).

Q17. What is parameterized SQL and why does it prevent injection? Concatenation lets input like ' OR '1'='1 change query structure. Prepared statements send template and values separately — the driver treats values as data, never SQL. Combine with input validation and least-privilege DB accounts.

Q18. Explain your Go TCP/Gin/sqlc project's request flow and where security fits. "Incoming HTTP hits Gin middleware (rate limiting, auth check, validation); handlers call sqlc-generated typed queries against PostgreSQL (parameterized by construction — no string-built SQL); errors map to generic client messages with details logged. TLS terminates at the load balancer; secrets come from a secret manager." (Tailor to your repo; expect follow-ups on middleware, connection pooling, and Judge0 sandbox isolation.)

Q19 (bonus). Binary search complexity and while (lo <= hi)? O(log n). lo <= hi because at lo == hi one candidate remains to test; lo < hi skips it. Always state your invariant.

Q20 (bonus). Threads in Python given the GIL? Fine for I/O-bound work (GIL released during I/O); CPU-bound needs multiprocessing; asyncio for high-concurrency I/O. Default build; 3.13+ offers an optional free-threaded build (PEP 703).


4. Code Snippets (interview-ready)

4.1 Stack via one queue (rotation; classic two-queue variant = O(1) push / O(n) pop)

Each push rotates older items behind the new one: push O(n), pop O(1).

from collections import deque

class StackViaQueues:
    def __init__(self):
        self.q = deque()
    def push(self, x):
        self.q.append(x)
        for _ in range(len(self.q) - 1):   # rotate so newest is at front
            self.q.append(self.q.popleft())
    def pop(self):
        return self.q.popleft()
    def top(self):
        return self.q[0]
    def empty(self):
        return not self.q
# push(1), push(2), pop() -> 2, top() -> 1   O(1) pop/top, O(n) push

4.2 Merge intervals

Sorting by start makes overlaps adjacent; max(...) handles contained intervals like [1,10] then [2,3].

def merge_intervals(intervals):
    intervals = sorted(intervals, key=lambda iv: iv[0])  # copy: avoid mutating caller; O(n log n)
    merged = []
    for s, e in intervals:
        if merged and s <= merged[-1][1]:    # overlap -> extend
            merged[-1][1] = max(merged[-1][1], e)
        else:
            merged.append([s, e])
    return merged

# [[1,3],[2,6],[8,10],[15,18]] -> [[1,6],[8,10],[15,18]]

4.3 Top-K frequent elements (heap + bucket alternative)

A size-k heap beats sorting all values: O(n log k); buckets give O(n) when counts are bounded by n.

import heapq
from collections import Counter

def top_k_frequent(nums, k):
    count = Counter(nums)                              # O(n)
    # size-k heap -> O(n log k); Counter.most_common(k) faster when k ~= n
    return [val for val, _ in heapq.nlargest(k, count.items(), key=lambda kv: kv[1])]

def top_k_bucket(nums, k):                             # O(n) bucket sort
    count = Counter(nums)
    buckets = [[] for _ in range(len(nums) + 1)]
    for val, c in count.items():
        buckets[c].append(val)
    out = []
    for freq in range(len(nums), -1, -1):
        out.extend(buckets[freq])
        if len(out) >= k:
            return out[:k]
    return out[:k]  # k > distinct values

4.4 BFS on a grid (shortest path / number of islands)

BFS expands in rings, so first arrival is fewest steps; DFS suits component counting.

from collections import deque

def shortest_path(grid, start, goal):          # 0 = open, 1 = wall
    if not grid or not grid[0]: return -1
    rows, cols = len(grid), len(grid[0])
    q = deque([(start[0], start[1], 0)])       # (r, c, dist)
    seen = {start}
    while q:
        r, c, d = q.popleft()
        if (r, c) == goal:
            return d
        for dr, dc in ((1,0),(-1,0),(0,1),(0,-1)):
            nr, nc = r + dr, c + dc
            if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 0 and (nr, nc) not in seen:
                seen.add((nr, nc))
                q.append((nr, nc, d + 1))
    return -1                                    # unreachable

def num_islands(grid):  # DFS counting; mutates grid (pass a copy); recursion ~O(cells) — use iterative BFS for large grids
    def sink(r, c):
        if 0 <= r < len(grid) and 0 <= c < len(grid[0]) and grid[r][c] == "1":
            grid[r][c] = "0"
            for dr, dc in ((1,0),(-1,0),(0,1),(0,-1)):
                sink(r + dr, c + dc)
            return 1
        return 0
    return sum(sink(r, c) for r in range(len(grid)) for c in range(len(grid[0])))

4.5 OOP live code — abstract Shape with virtual dispatch

The base class owns validation; subclasses supply only area().

// Java: abstraction + inheritance + polymorphism + encapsulation
abstract class Shape {
    private String color;                       // encapsulated
    protected Shape(String color) { setColor(color); }
    public String getColor() { return color; }
    public final void setColor(String color) {  // validation in ONE place
        if (color == null || color.isBlank()) throw new IllegalArgumentException("color required");
        this.color = color;
    }
    public abstract double area();              // forces subclasses to implement
    @Override public String toString() {
        return getClass().getSimpleName() + "(" + color + ", area=" + String.format("%.2f", area()) + ")";
    }
}

class Circle extends Shape {
    private final double r;
    public Circle(String color, double r) { super(color); this.r = r; }
    @Override public double area() { return Math.PI * r * r; }   // runtime binding
}

class Rectangle extends Shape {
    private final double w, h;
    public Rectangle(String color, double w, double h) { super(color); this.w = w; this.h = h; }
    @Override public double area() { return w * h; }
}

public class Demo {
    public static void main(String[] args) {
        Shape s = new Circle("red", 2);         // declared Shape, actual Circle
        System.out.println(s.area());           // 12.566... -> dynamic dispatch (vtable)
        java.util.List<Shape> shapes = java.util.List.of(s, new Rectangle("blue", 3, 4)); // List.of = Java 9+; use Arrays.asList on Java 8
        shapes.forEach(System::println);        // polymorphism: same code, different behavior
    }
}
// C++: pure virtual + virtual destructor
#include <iostream>
#include <vector>
#include <memory>
class Shape {
public:
    virtual double area() const = 0;            // pure virtual -> abstract class
    virtual ~Shape() = default;                 // ALWAYS virtual dtor in base
};
class Circle : public Shape {
    double r;
public:
    explicit Circle(double r) : r(r) {}
    double area() const override { return 3.14159 * r * r; }
};
int main() {
    std::vector<std::unique_ptr<Shape>> v;
    v.push_back(std::make_unique<Circle>(2.0));
    std::cout << v[0]->area();                  // dynamic binding via vtable
}

4.6 Parameterized SQL (vs injection)

The driver keeps template and values separate, so a value can never change the query's parse tree.

import psycopg2

# BAD — SQL injection: name = "x' OR '1'='1" dumps the table
# cur.execute(f"SELECT * FROM users WHERE name = '{name}'")

# GOOD — parameterized query: input is data, never SQL
def find_user(conn, name, min_age):
    with conn.cursor() as cur:
        cur.execute(
            "SELECT id, name, email FROM users WHERE name = %s AND age >= %s",
            (name, min_age),
        )
        return cur.fetchall()
-- Classic: second-highest salary
SELECT MAX(salary) AS second_highest
FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);
-- or: SELECT DISTINCT salary FROM employees ORDER BY salary DESC OFFSET 1 LIMIT 1;
-- Latest entry per user (window function)
SELECT user_id, entry_date FROM (
  SELECT user_id, entry_date, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY entry_date DESC, id DESC) rn
  FROM logs) t WHERE rn = 1;

4.7 Queue via stacks + 3-schedule intersection + range-shift pattern

The output stack refills only when empty, so each element moves once: amortized O(1) pop.

class QueueViaStacks:  # push O(1), pop amortized O(1)
    def __init__(self): self.a, self.b = [], []
    def push(self, x): self.a.append(x)
    def pop(self):
        if not self.b:
            while self.a: self.b.append(self.a.pop())
        return self.b.pop()
  • 3 free slots (N users): sort each list, 3-pointer sweep — overlap = [max(starts), min(ends)] if valid; advance the list ending earliest. O(n log n) sort + O(n) sweep.
  • Right-shift [l,r] × q queries: difference array diff[l]+=v; diff[r+1]-=v, one prefix pass to finalize — O(1) per update, O(n+q) total; rotation by reversal as fallback.

5. Revision Table (last-24-hours sheet)

# Topic Golden answer anchor Time
1 OA format 10–25 MCQs + 2–3 DSA, 60–90 min (varies: HirePro/HackerEarth/Sparkplug) 5 min
2 Language quirks Java pass-by-value-of-ref; C pointers; Python mutability; Go slices copy headers 10 min
3 OOP pillars Encapsulation/Abstraction/Inheritance/Polymorphism + Shape example 10 min
4 Virtual/binding Overload=static, Override=dynamic (vtable); pure virtual = abstract; virtual dtor 5 min
5 DSA patterns hash/2ptr/window/intervals/stack/heap/BS/BFS/DFS/DP → complexity map 15 min
6 Narration script constraints → brute (state complexity) → optimize → dry run → edge cases 5 min
7 OS proc vs thread; paging translation; FIFO vs LRU; deadlock 4 conditions; schedulers 15 min
8 DBMS 1NF→BCNF; ACID; index trade-off; JOINs; SQL vs NoSQL table 15 min
9 SQL queries second-highest salary; latest-per-user; all JOINs on 2 small tables 10 min
10 Secure coding validation, parameterized SQL, encoding, auth (argon2), generic errors, least privilege 10 min
11 Git/Docker/CI branch→PR→merge; image vs container; pipeline w/ SAST + CVE gating 10 min
12 Resume tech Go TCP/Gin/sqlc flow; Judge0 sandbox isolation; why each stack choice 15 min
13 Practice set 18 problems in §2.4 — re-solve 3 hardest blind 60 min

6. Common Mistakes (and fixes)

  1. Silent coding. Fix: narrate every decision — "hash map for O(1) lookup, so O(n) total." Interviewers reward thought process over speed.
  2. Jumping to code before stating complexity. Fix: always say brute force + why it fails + target complexity from constraints (n ≤ 10⁵ → O(n log n)).
  3. Ignoring edge cases. Fix: empty input, single element, duplicates, negatives, overflow, unicode strings — list them before the dry run.
  4. Wrong off-by-one in binary search / intervals. Fix: write the loop invariant; test on 1- and 2-element arrays immediately.
  5. Forgetting virtual destructor or claiming Java has pointers. Fix: Java has references (no pointer arithmetic); polymorphic C++ bases need virtual ~Base().
  6. Mixing up overloading (compile-time) and overriding (runtime). Fix: overload = same name different args; override = subclass replaces parent method.
  7. String-building SQL queries "just for a demo". Fix: always write prepared statements even in interviews — for a cybersecurity role this is a direct evaluation point.
  8. Weak normalization explanation. Fix: name the dependency each normal form removes (partial for 2NF, transitive for 3NF), not just the rule.
  9. Claiming "NoSQL is better" without a trade-off. Fix: tie the choice to consistency + relations vs scale + schema flexibility (payments vs catalog).
  10. Not knowing your own resume. Fix: every JD keyword (Go, Gin, sqlc, Judge0, Rust, TS) needs a 30-second story: why chosen, hardest bug, security angle. Rounds start with "walk me through your project."
  11. MCQ time sink. Fix: ~90 sec/question; mark and move — cumulative score of MCQ + coding decides the shortlist.
  12. Fumbling syntax during live code. Fix: rewrite your 10 most common solutions in ONE language until syntax is automatic; declare it your strongest language up front.
  13. Ignoring memory-safety questions (C/C++/Rust). Fix: know malloc/free vs smart pointers vs Rust ownership — frame buffer overflows as the classic C vulnerability you'd hunt in an audit.
  14. No dry run. Fix: after coding, trace a 3-element example aloud line by line — it catches most self-bugs before the interviewer does.

Sources: candidate-reported Walmart Global Tech experiences (GeeksforGeeks 2021–2025, LeetCode Discuss, HackerRank OA 2026). Confirm your section timings from the drive mail.

Saved in this browser only.