A classmate claims that CSS Flexbox and CSS Grid are interchangeable — "anything you can do with Grid, you can do with Flexbox." Given that Flexbox uses 'display: flex' and Grid uses 'display: grid', evaluate this claim and compare their layout algorithms. When would you specifically choose Grid over Flexbox?
The claim is false. Flexbox is one-dimensional (row OR column), while Grid is two-dimensional (rows AND columns simultaneously). Choose Grid for: page-level layouts with header/sidebar/main/footer, image galleries with uniform cells, or any layout requiring alignment in both axes. Choose Flexbox for: navigation bars, centering items, or distributing space in a single row/column
The claim is true. Flexbox can achieve any Grid layout by nesting multiple flex containers, making Grid redundant. Always use Flexbox for simpler code
The claim is false, but in the opposite way — Grid can do everything Flexbox can, making Flexbox redundant. Modern developers should only use Grid
The claim is true because both Flexbox and Grid use the same underlying browser rendering engine, so they produce identical results for any layout
Answer: A. The claim is false. Flexbox is one-dimensional (row OR column), while Grid is two-dimensional (rows AND columns simultaneously). Choose Grid for: page-level layouts with header/sidebar/main/footer, image galleries with uniform cells, or any layout requiring alignment in both axes. Choose Flexbox for: navigation bars, centering items, or distributing space in a single row/column
ExplanationFlexbox operates in 1 dimension at a time: you can make a row of items or a column, but not both simultaneously. Grid operates in 2 dimensions: you define rows AND columns (e.g., grid-template-columns: 200px 1fr 200px), then place items in specific cells. This is why the claim is false — because Flexbox cannot natively handle 2D layouts without nesting. For a school website: use Grid for the overall page layout (header spanning full width across 3 columns, sidebar + main content, footer at bottom). Use Flexbox for the navigation links inside the header (e.g., justify-content: space-between distributes 5 nav items evenly). They complement each other — over 97% of professional sites use both, resulting in cleaner and more maintainable CSS.
Question 102 · Input Normalization · medium
You are building a simple chatbot using if-elif chains in Python. A user types "What is AI?" and your chatbot should respond. Which approach correctly implements case-insensitive matching, and why is normalization important?
Use 'if user_input.lower() == "what is ai?"' to normalize the input to lowercase before comparison. This handles "What is AI?", "WHAT IS AI?", "what is ai?", and all other case variations. Without normalization, each casing would need a separate elif branch — exponentially many possibilities
Use 'if user_input == "What is AI?" or user_input == "what is ai?"' and list every possible casing combination. There are only a few realistic variations to handle
Use 'if user_input.upper() == user_input.lower()' to detect case-insensitive strings. If the input passes this test, it matches any expected phrase automatically
Use 'if "ai" in user_input' alone. The 'in' operator is case-insensitive by default in Python, so this matches any casing of the input string
Answer: A. Use 'if user_input.lower() == "what is ai?"' to normalize the input to lowercase before comparison. This handles "What is AI?", "WHAT IS AI?", "what is ai?", and all other case variations. Without normalization, each casing would need a separate elif branch — exponentially many possibilities
Explanationlower() converts any string to all-lowercase: "What is AI?" becomes "what is ai?". Comparing the lowered input against a lowercase target handles ALL case variations with one check. Without normalization, "What is AI?" has 2^8 possible case combinations (each of the 8 alphabetic characters — W, h, a, t, i, s, A, I — can independently be upper or lower). The 'in' operator is NOT case-insensitive — 'AI' in 'what is ai?' returns False. Normalization (lowering, stripping whitespace, removing punctuation) is the first step in any text processing pipeline.
Question 103 · Web Performance Optimization · medium
Your school's website loads slowly. The Chrome DevTools Network tab shows: index.html (2 KB, 50ms), style.css (15 KB, 200ms), hero-image.jpg (3.2 MB, 4.5s), script.js (80 KB, 300ms). Analyze these load times — what is the output bottleneck, and how would you design a fix using compression and responsive images?
The hero-image.jpg at 3.2 MB / 4.5s is the clear bottleneck — it is roughly 1,600x larger than the HTML and accounts for 89% of total load time. Fix 1: Compress the image using WebP format (typically 25-35% smaller than JPEG). Fix 2: Use responsive images with srcset to serve smaller versions on mobile devices. Additional: lazy-load images below the fold
The style.css at 200ms is the bottleneck because CSS blocks rendering. The image loads asynchronously and does not affect page speed
The script.js at 80 KB is the bottleneck because JavaScript is always the slowest resource type on any web page, regardless of file size
All resources are equally responsible. The fix is to upgrade the web hosting server to a faster tier, as individual file optimization has negligible impact
Answer: A. The hero-image.jpg at 3.2 MB / 4.5s is the clear bottleneck — it is roughly 1,600x larger than the HTML and accounts for 89% of total load time. Fix 1: Compress the image using WebP format (typically 25-35% smaller than JPEG). Fix 2: Use responsive images with srcset to serve smaller versions on mobile devices. Additional: lazy-load images below the fold
ExplanationThe 3.2 MB image dominates: it is 97% of total payload (3.2 MB out of 3.3 MB) and 89% of load time (4.5s out of 5.05s). Techniques: (1) Convert to WebP — a 3.2 MB JPEG typically becomes about 2.1-2.4 MB in WebP, a 25-35% reduction. (2) Resize — a hero image rarely needs to be wider than 1920px; many source images are 4000px+. (3) Use <img srcset="..."> for responsive sizing. (4) Add loading="lazy" for below-fold images. These are Core Web Vitals best practices that Google uses for search ranking.
Question 104 · HTTP Status Codes · hard
In your school's event management system API using 'app.get("/api/events/:id", handler)', a student queries '/api/events/999'. Compare what happens when the server returns a 404 response vs a 500 response — what is the output in each scenario, and how would you implement the correct error handling?
404 means "Not Found" — event with ID 999 does not exist in the database. The server processed the request correctly but found no matching resource. 500 means "Internal Server Error" — something crashed on the server (e.g., database connection failed, unhandled exception). 404 is a client-side issue (bad ID), 500 is a server-side bug
404 means the API endpoint '/api/events' does not exist. 500 means event 999 was not found. The numbers are inversely mapped to indicate severity
404 and 500 are interchangeable error codes. Servers can use either one for any error, and clients treat them identically
404 means the student's browser is outdated and cannot reach the server. 500 means the server is overloaded with too many requests and needs to be restarted
Answer: A. 404 means "Not Found" — event with ID 999 does not exist in the database. The server processed the request correctly but found no matching resource. 500 means "Internal Server Error" — something crashed on the server (e.g., database connection failed, unhandled exception). 404 is a client-side issue (bad ID), 500 is a server-side bug
ExplanationHTTP status codes communicate what happened: 2xx = success (200 OK), 4xx = client error (404 Not Found), 5xx = server error (500 Internal Server Error). A 404 returns because the resource (event 999) does not exist — the client asked for something that is not there. The output is: res.status(404).json({error: 'Event not found'}). A 500 returns because the server encountered an unexpected condition — a bug, crash, or database connection failure. The output is an automatic 500 with stack trace in dev mode. The distinction matters: 404 tells the client to check their request (yields a "not found" message); 500 tells the client to retry later (produces an "internal error" response). In Express.js, proper implementation uses try-catch: try { const event = await db.findById(999); if (!event) return res.status(404).json({error: 'Not found'}); } catch(err) { res.status(500).json({error: 'Server error'}); }.
Question 105 · DFS vs BFS Traversal · hard
You implement DFS (depth-first search) on a tree representing a file system. Starting from root '/', with children: / → [home, var, etc], home → [user1, user2], user1 → [docs, pics]. What is the DFS traversal order using a stack, and how does it differ from BFS?
DFS order: /, etc, var, home, user2, user1, pics, docs (stack-based, right-to-left push). DFS explores as deep as possible before backtracking. BFS would give: /, home, var, etc, user1, user2, docs, pics — level by level. DFS uses a stack (LIFO) while BFS uses a queue (FIFO), producing fundamentally different traversal patterns
DFS and BFS produce the same traversal order on trees — the difference only matters for graphs with cycles. Both give /, home, var, etc, user1, user2, docs, pics
DFS order: docs, pics, user1, user2, home, var, etc, /. DFS always starts from the deepest leaf node and works upward toward the root
DFS order: /, home, user1, docs — DFS stops after reaching the first leaf node and does not visit any other branches of the tree
Answer: A. DFS order: /, etc, var, home, user2, user1, pics, docs (stack-based, right-to-left push). DFS explores as deep as possible before backtracking. BFS would give: /, home, var, etc, user1, user2, docs, pics — level by level. DFS uses a stack (LIFO) while BFS uses a queue (FIFO), producing fundamentally different traversal patterns
ExplanationStack-based DFS: push /. Pop / → visit /, then push its children [home, var, etc] onto the stack in left-to-right order (push home, then var, then etc), which puts etc — the rightmost child — on top. Pop etc (leaf). Pop var (leaf). Pop home → visit home, then push its children [user1, user2] in left-to-right order (push user1, then user2), putting user2 on top. Pop user2 (leaf). Pop user1 → visit user1, then push its children [docs, pics] in left-to-right order (push docs, then pics), putting pics on top. Pop pics (leaf). Pop docs (leaf). Resulting order: /, etc, var, home, user2, user1, pics, docs. Because each level's children are pushed left-to-right, the rightmost child always lands on top of the stack, so this stack-based DFS visits children right-to-left at every level — the reverse of the left-to-right order a straightforward recursive DFS would produce. BFS with a queue instead gives level-order: /, home, var, etc, user1, user2, docs, pics. DFS uses O(h) memory (h = height of the tree), while BFS uses O(w) memory (w = maximum width); for deep, narrow trees DFS is the more memory-efficient choice.
Question 106 · HTTP Methods and Form Security · hard
You create an HTML form: '<form method="POST" action="/submit"><input name="email" type="email"><button type="submit">Go</button></form>'. Compare what happens when method="POST" vs method="GET" — how would you evaluate which is appropriate for submitting a password reset form?
POST sends data in the request body (hidden from URL). GET appends data to the URL: /submit?email=user@mail.com — visible in browser history, server logs, and bookmarks. For password reset, POST is mandatory because GET would expose the email in the URL, which gets logged in proxy servers, shared in browser history, and cached. POST data is not cached or bookmarked
POST and GET are identical in security — both encrypt data using HTTPS. The only difference is that GET is faster because it sends less metadata in the request headers
GET sends data in the request body while POST appends it to the URL. This is why GET is more secure and should always be used for sensitive forms
POST is only for creating new database records while GET is only for reading data. Neither method should be used for password reset — a custom HTTP method called RESET is required
Answer: A. POST sends data in the request body (hidden from URL). GET appends data to the URL: /submit?email=user@mail.com — visible in browser history, server logs, and bookmarks. For password reset, POST is mandatory because GET would expose the email in the URL, which gets logged in proxy servers, shared in browser history, and cached. POST data is not cached or bookmarked
ExplanationGET appends form data to the URL as query parameters: /submit?email=user@mail.com. This data appears in browser history, server access logs (100% of web servers log URLs), referer headers, and can be bookmarked. POST sends data in the request body, which is not logged in URLs. For password reset: the email is PII (personally identifiable information). Exposing it in the URL means every proxy server, CDN, and analytics tool that logs URLs would capture it, because URL logging is on by default in 99% of server configurations. POST avoids this since the body is not logged by default. Note: neither GET nor POST is encrypted on its own — HTTPS encrypts both, but the URL path (up to 2048 characters) is still logged at the server level even with HTTPS.
Question 107 · Adjacency Matrix Analysis · hard
You have an adjacency matrix for a 4-node directed graph: [[0,1,0,0],[0,0,1,1],[1,0,0,0],[0,0,1,0]]. Node labels are A=0, B=1, C=2, D=3. How many edges does this graph have, and what is the in-degree of node C?
5 edges total. Reading row by row: A→B (1 edge), B→C and B→D (2 edges), C→A (1 edge), D→C (1 edge). In-degree of C = count 1s in column 2 = matrix[1][2] + matrix[3][2] = 1+1 = 2 (edges from B and D point to C). Out-degree of C = count 1s in row 2 = 1 (C→A only)
4 edges total. The diagonal is always counted as edges in adjacency matrices, giving one self-loop per node, and the in-degree of C is 4
8 edges total. Each 1 in the matrix represents a bidirectional edge, so you count each 1 twice. In-degree of C is 4
5 edges total, but in-degree of C is 0 because in-degree counts only edges originating from C, not edges pointing to C
Answer: A. 5 edges total. Reading row by row: A→B (1 edge), B→C and B→D (2 edges), C→A (1 edge), D→C (1 edge). In-degree of C = count 1s in column 2 = matrix[1][2] + matrix[3][2] = 1+1 = 2 (edges from B and D point to C). Out-degree of C = count 1s in row 2 = 1 (C→A only)
ExplanationIn a directed adjacency matrix, matrix[i][j] = 1 means edge from node i to node j. Count all 1s: row 0 has 1 (A→B), row 1 has 2 (B→C, B→D), row 2 has 1 (C→A), row 3 has 1 (D→C). Total = 5 edges. In-degree of node C (column 2): check matrix[0][2]=0, matrix[1][2]=1 (B→C), matrix[2][2]=0, matrix[3][2]=1 (D→C). This produces the result that in-degree = 2 because exactly 2 edges point to C. Out-degree of node C (row 2): matrix[2][0]=1 (C→A), rest are 0. Out-degree = 1. For undirected graphs, the matrix is symmetric; for directed graphs, it typically is not. Space complexity: O(V^2) = 16 cells for 4 nodes, regardless of edge count.
Question 108 · Graph Coloring and Scheduling · hard
In a school timetable scheduling problem, each class needs a room and time slot. You model this as a graph coloring problem where nodes = classes and edges = conflicts (same teacher or students). If the chromatic number is 4, what does this tell you about the minimum number of time slots needed?
The minimum number of time slots needed is 4. Each color represents a time slot, and connected nodes (conflicting classes) get different colors. Chromatic number 4 means no valid schedule exists with fewer than 4 slots because there exist 4 classes with mutual conflicts. This is the same algorithm used for exam scheduling, register allocation in compilers, and frequency assignment in telecom
The chromatic number 4 means 4 rooms are needed, not 4 time slots. Colors represent rooms, and conflicting classes are placed in different rooms regardless of timing
The minimum time slots is 2 because graph coloring always reduces the chromatic number by half when applied to scheduling problems
The chromatic number 4 means the graph has exactly 4 nodes, which is unrelated to the number of time slots. Time slots are determined by counting edges
Answer: A. The minimum number of time slots needed is 4. Each color represents a time slot, and connected nodes (conflicting classes) get different colors. Chromatic number 4 means no valid schedule exists with fewer than 4 slots because there exist 4 classes with mutual conflicts. This is the same algorithm used for exam scheduling, register allocation in compilers, and frequency assignment in telecom
ExplanationGraph coloring maps directly to scheduling: each color = 1 time slot. If two classes conflict (same teacher/students), they share an edge and MUST get different colors (different time slots). The chromatic number χ(G) is the minimum number of colors needed. χ(G) = 4 means at least 4 time slots are required because there exists a subgraph (like K4, complete graph on 4 nodes) where every pair conflicts. Finding the exact chromatic number is NP-hard, but greedy algorithms give good approximations. Real-world use: IIT/NIT exam scheduling uses graph coloring for 5000+ students across 100+ courses.
Question 109 · Linear Regression Interpretation · medium
You train a simple linear regression model to predict house prices in Mumbai. After training, the model gives: price = 0.85 * area_sqft + 12.5 (in lakhs). Given that a flat has area 1000 sqft, what is the predicted price, and how would you evaluate whether the coefficient 0.85 is reasonable?
Predicted price = 0.85 * 1000 + 12.5 = 862.5 lakhs (approx 8.6 crore). The coefficient 0.85 means each additional sqft adds 0.85 lakhs (85,000 rupees) to the price. For prime Mumbai locations (Bandra, Worli), this is realistic where rates are 70,000-1,00,000/sqft. The intercept 12.5 represents the base price independent of area (land value, amenities). Evaluation: check R-squared, residual plots, and compare against actual Magicbricks/99acres listings
Predicted price = 0.85 + 1000 + 12.5 = 1013.35 lakhs. The coefficient is multiplied by nothing — it represents a fixed additional cost
Predicted price = 0.85 * 1000 = 850 lakhs. The intercept 12.5 is a training artifact and should be ignored in predictions
Predicted price cannot be computed because linear regression does not work for house prices — only neural networks can capture the non-linear relationship between area and price
Answer: A. Predicted price = 0.85 * 1000 + 12.5 = 862.5 lakhs (approx 8.6 crore). The coefficient 0.85 means each additional sqft adds 0.85 lakhs (85,000 rupees) to the price. For prime Mumbai locations (Bandra, Worli), this is realistic where rates are 70,000-1,00,000/sqft. The intercept 12.5 represents the base price independent of area (land value, amenities). Evaluation: check R-squared, residual plots, and compare against actual Magicbricks/99acres listings
ExplanationLinear model: y = mx + b. price = 0.85 * 1000 + 12.5 = 862.5 lakhs. The coefficient 0.85 is the slope — each sqft adds 85,000 rupees. In Mumbai's premium areas (Bandra, Powai, Lower Parel), actual rates range from 30,000-1,50,000/sqft, making 85,000 a plausible mid-range estimate. The intercept 12.5 lakhs captures non-area factors (building age, floor, view). To evaluate model quality: R-squared > 0.7 indicates good fit, residual plots should show no patterns, and predictions should be within 15-20% of actual listings on property portals. Multiple regression adding bedrooms, floor, and age would improve accuracy.
Question 110 · JavaScript Type Coercion · medium
In JavaScript, consider this code: 'console.log(typeof null); console.log(typeof undefined); console.log(null == undefined); console.log(null === undefined);'. What is the output of each console.log statement, and how would you evaluate why typeof null returns a surprising result that differs from what most developers expect?
Output: 'object', 'undefined', true, false. typeof null returns 'object' — this is a known JavaScript bug from 1995 that was never fixed for backward compatibility. typeof undefined returns 'undefined'. null == undefined is true because loose equality treats them as equivalent "empty" values. null === undefined is false because strict equality checks type too, and they are different types
Output: 'null', 'undefined', false, false. typeof null correctly returns 'null', and null is never equal to undefined under any comparison operator
Output: 'object', 'undefined', true, true. Both == and === treat null and undefined identically because they are semantically the same value in JavaScript
Output: 'undefined', 'undefined', true, true. Both null and undefined have the same type ('undefined') and the same value, making all comparisons return true
Answer: A. Output: 'object', 'undefined', true, false. typeof null returns 'object' — this is a known JavaScript bug from 1995 that was never fixed for backward compatibility. typeof undefined returns 'undefined'. null == undefined is true because loose equality treats them as equivalent "empty" values. null === undefined is false because strict equality checks type too, and they are different types
Explanationtypeof null === 'object' is JavaScript's most famous bug — in the original implementation, values were stored as type tag + value. null was stored as a NULL pointer (0x00), and objects also had type tag 0, causing typeof to misidentify null as 'object'. This was never fixed because millions of websites depend on this behavior. typeof undefined === 'undefined' is correct. Loose equality (==) performs type coercion: the spec specifically defines null == undefined as true (they're both "empty" values). Strict equality (===) requires same type AND same value: null (object) !== undefined (undefined), so false. Rule: always use === in JavaScript to avoid coercion surprises.
Question 111 · REST API Design Conventions · hard
You design a school attendance API with these endpoints: GET /api/students (list all), GET /api/students/42 (one student), POST /api/students (create), PUT /api/students/42 (update), DELETE /api/students/42 (remove). Evaluate whether this follows REST conventions — what is the output status code for a successful POST?
This follows REST conventions perfectly. GET returns resources (200 OK), POST creates a new resource and returns 201 Created with a Location header pointing to the new resource (e.g., /api/students/43). PUT updates an existing resource and returns 200 OK. DELETE removes and returns 204 No Content. The URL noun 'students' (not verb 'getStudents') and HTTP method as the verb is core REST design
This does not follow REST because the URLs should contain verbs: /api/getStudents, /api/createStudent, /api/deleteStudent/42. Status code for POST is 200 OK
This follows REST but the POST should return 301 Moved Permanently to redirect to the new resource. REST requires redirects after creation
This violates REST because a single endpoint /api/students cannot handle multiple HTTP methods. Each method needs its own URL: /api/students/list, /api/students/create, etc.
Answer: A. This follows REST conventions perfectly. GET returns resources (200 OK), POST creates a new resource and returns 201 Created with a Location header pointing to the new resource (e.g., /api/students/43). PUT updates an existing resource and returns 200 OK. DELETE removes and returns 204 No Content. The URL noun 'students' (not verb 'getStudents') and HTTP method as the verb is core REST design
ExplanationREST (Representational State Transfer) principles: (1) URLs are nouns representing resources (/students, not /getStudents). (2) HTTP methods are verbs: GET=read, POST=create, PUT=update, DELETE=remove. (3) Status codes communicate results: 200 OK (success), 201 Created (new resource + Location header), 204 No Content (successful delete, empty body), 404 Not Found, 422 Unprocessable Entity (validation error). A successful POST returns 201 Created with the new resource in the body and Location: /api/students/43 in the headers. This is the standard convention used by GitHub, Stripe, and Razorpay APIs.
Question 112 · Object-Oriented Programming: Thinking in Objects · hard
A college fest committee is tracking prepaid UPI-style wallets for three volunteers using the `Wallet` class below. Trace the code carefully — remember that in Python, a variable holding an object stores a *reference* to it, so assignment can create an alias rather than an independent copy.
```python
class Wallet:
def __init__(self, balance):
self.balance = balance # balance in rupees
priya_wallet = Wallet(500)
neha_wallet = priya_wallet # neha_wallet now refers to the SAME object as priya_wallet
raj_wallet = Wallet(700) # a completely separate, independent object
neha_wallet.balance += 200
print(priya_wallet.balance == raj_wallet.balance)
print(priya_wallet is neha_wallet)
print(priya_wallet == raj_wallet)
```
In the exact order the three `print` statements execute, what does this code output?
True, True, True — every one of the three checks succeeds since the balances and identities all line up.
False, False, False — none of the three checks succeed because neha_wallet never actually shares priya_wallet's balance update.
True, True, False — the wallets end up with equal balances and the same identity, but the default equality check still fails.
True, False, False — the balances end up equal, but changing the balance attribute is treated as breaking the shared identity.
Answer: C. True, True, False — the wallets end up with equal balances and the same identity, but the default equality check still fails.
ExplanationThe line `neha_wallet = priya_wallet` does not build a new Wallet — it makes neha_wallet a second name for the exact same object priya_wallet already points to (aliasing). `raj_wallet = Wallet(700)`, by contrast, builds a genuinely separate object with its own balance. When `neha_wallet.balance += 200` runs, it updates the balance stored inside that one shared object, so priya_wallet.balance changes too — both now read ₹700, since priya_wallet and neha_wallet are just two labels on the same data. That makes `priya_wallet.balance == raj_wallet.balance` evaluate to True, because 700 equals 700. The identity check `priya_wallet is neha_wallet` is also True, because `is` checks whether two names point to the identical object in memory, not whether their attribute values match — and here they do point to the same object. The last line is where the trap lies: the Wallet class never defines a custom `__eq__` method, so Python falls back to the default equality inherited from `object`, which — just like `is` — compares object identity rather than attribute values. Since priya_wallet and raj_wallet are two distinct objects (even though their balances now happen to both be ₹700), `priya_wallet == raj_wallet` returns False. The lesson: without an explicit `__eq__`, equal-looking objects are still "not equal" in Python unless they are literally the same object.
Question 113 · Neural Networks: How the Brain Inspired Computers · hard
A biological neuron only fires an electrical signal once the combined input from all its dendrites crosses a threshold — a single strong signal doesn't guarantee firing, and a single weak or inhibitory one doesn't block it either; what matters is the net total. The Python function below models this same all-or-nothing decision for one artificial neuron:
```python
def neuron_output(x1, x2, x3, w1, w2, w3, bias):
total = (x1 * w1) + (x2 * w2) + (x3 * w3) + bias
return 1 if total >= 0 else 0
```
If you call `neuron_output(0.4, 0.7, 0.3, 0.6, -0.3, 0.5, -0.25)`, what value does it return, and why?
It returns 0 — the weighted sum (0.6×0.4 + (−0.3)×0.7 + 0.5×0.3 = 0.18) plus the bias (−0.25) equals −0.07, which is below the firing threshold of 0, so the function returns 0.
It returns 1 — the weighted sum alone (0.18) is already positive, and since a bias term only shifts a neuron's output up or down slightly rather than being able to change whether it fires, the neuron fires regardless.
It returns 1 — a negative weight simply removes that input's term from the calculation, so the sum becomes 0.6×0.4 + 0.5×0.3 + (−0.25) = 0.14, which is positive and causes the neuron to fire.
It returns 1 — the unweighted inputs (0.4 + 0.7 + 0.3 = 1.4) are far larger than the bias (0.25), and since weights only control how strongly a neuron fires rather than whether it fires at all, the large combined input guarantees firing.
Answer: A. It returns 0 — the weighted sum (0.6×0.4 + (−0.3)×0.7 + 0.5×0.3 = 0.18) plus the bias (−0.25) equals −0.07, which is below the firing threshold of 0, so the function returns 0.
ExplanationA biological neuron integrates signals from all its dendrites and only fires an action potential once the combined signal crosses a threshold — the net total is what decides firing, not any single input in isolation. The code models this directly: it multiplies each input by its weight, sums the three products, adds the bias, and checks whether that final total is at least 0.
Working through the numbers: 0.6×0.4 = 0.24, (−0.3)×0.7 = −0.21, and 0.5×0.3 = 0.15, so the three weighted terms sum to 0.24 − 0.21 + 0.15 = 0.18. Adding the bias of −0.25 gives 0.18 + (−0.25) = −0.07. Since −0.07 is less than 0, the condition `total >= 0` evaluates to False, so the function returns 0 — the artificial neuron does not fire.
The bias is not a minor adjustment layered on top of a decision the weighted sum has already made — it is exactly what tips this neuron from firing to not firing, since the weighted sum alone (0.18) is positive but the bias pulls the total below zero. A negative weight is also not an instruction to drop that input from the calculation; it means the input actively suppresses firing, and its full signed product (−0.21) must be subtracted from the total, not ignored, which is why treating it as absent gives the wrong sum (0.14) and the wrong outcome. And weights are not a separate "intensity" layer that leaves the fire/no-fire decision to the raw, unweighted inputs — the threshold check only ever looks at the final weighted, signed total, so a large unweighted sum like 1.4 has no bearing on the decision at all.
Question 114 · Version Control with Git: How Professional Developers Work · hard
Rohan is working in a Git repository for his college coding-club project. The initial commit is A, followed by commit B on main. At commit B, a new branch called feature is created. Two more commits, C and D, are made on feature. Meanwhile, back on main, one more commit, E, is made directly on main (feature never sees E). Rohan then checks out main and runs:
```
git merge feature
```
Counting the initial commit and any new commit Git creates during this operation, how many commits exist in main's history immediately after the merge finishes, and why doesn't Git simply move main's branch pointer forward to match feature?
Six commits — A, B, E, C, D, plus one new merge commit — because main advanced with commit E after branching, so the two branches diverged and Git must join them with a merge commit that has two parent commits.
Five commits — A, B, E, C, D — because feature already contains every commit main needs, so Git simply fast-forwards main's pointer to D without creating any merge commit.
Seven commits, because Git must recreate C and D as brand-new commits on top of E before recording a merge commit, keeping the originals as well so the full history is preserved twice.
Four commits — A, B, C, D — because merging feature into main replaces main's own commit E with feature's history, and no separate merge commit is needed since feature is the branch supplying new work.
Answer: A. Six commits — A, B, E, C, D, plus one new merge commit — because main advanced with commit E after branching, so the two branches diverged and Git must join them with a merge commit that has two parent commits.
Explanationmain and feature both started from the same commit B, so B is their shared ancestor. After the branch was created, main moved forward on its own with commit E, while feature moved forward independently with C and D. Because main's tip (E) is not an ancestor of feature's tip (D), and D is likewise not an ancestor of E, the two branches have diverged — a fast-forward is only possible when the branch being merged in already contains every commit the current branch has, and here main has E, which feature lacks. So Git instead performs a three-way merge: it compares the changes made since the common ancestor B on both sides and creates a brand-new merge commit with two parents, E and D. That merge commit sits on top of the existing history without altering or duplicating any of the five original commits (A, B, E, C, D), bringing the total commit count in main's history to six.
Question 115 · Graph Algorithms: Networks and Connections · hard
A telecom company is testing a message-relay network connecting five data centers: Surat (S), Chennai (C), Agra (A), Bhopal (B), and Dehradun (D). Because uplink and downlink capacities differ, every link is one-way, with a fixed transmission delay in milliseconds:
```
S → A : 10 ms
S → C : 3 ms
C → A : 4 ms
C → B : 8 ms
C → D : 2 ms
A → B : 2 ms
D → B : 9 ms
```
Using Dijkstra's algorithm, what is the minimum total delay for a message sent from S to B, and which route achieves it?
9 ms, via S → C → A → B
11 ms, via S → C → B
12 ms, via S → A → B
14 ms, via S → C → D → B
Answer: A. 9 ms, via S → C → A → B
ExplanationRun Dijkstra's algorithm starting from S, tracking the best-known distance to every node.
Initial distances: S = 0, and A, B, C, D = infinity.
Visit S (distance 0): relax its edges. A becomes 10, C becomes 3.
Visit C (distance 3, the smallest unvisited value): relax C's edges. A improves from 10 to 3 + 4 = 7. B becomes 3 + 8 = 11. D becomes 3 + 2 = 5.
Visit D (distance 5, now the smallest unvisited value): D's only outgoing edge goes to B, giving 5 + 9 = 14, which is worse than B's current value of 11, so B stays at 11.
Visit A (distance 7, the smallest unvisited value): relax A's edge to B, giving 7 + 2 = 9, which improves B from 11 down to 9.
Visit B (distance 9, the smallest unvisited value): B has no outgoing edges to relax, and every node is now finalized.
The minimum delay from S to B is 9 ms, along the route S → C → A → B (3 + 4 + 2 = 9). This is exactly why Dijkstra's algorithm keeps every node's distance tentative until that node is actually selected as the current minimum: the direct-looking two-hop routes S → C → B (11 ms) and S → A → B (12 ms) both look cheaper at first glance, but the three-hop route through C and A ends up cheaper once all the relaxations are carried out. Stopping the search as soon as any path to B is found, or trusting the path with the fewest hops, are the two most common mistakes that lead to the wrong answer here.
Question 116 · Data Science with Pandas: Analyzing Real Data · hard
A shopkeeper's UPI settlement app exports one day's transactions into a pandas DataFrame `df` with columns `City` and `Amount` (in ₹), covering payments received across three cities. Trace this code by hand:
```python
import pandas as pd
df = pd.DataFrame({
"City": ["Delhi", "Mumbai", "Delhi", "Pune", "Mumbai", "Delhi", "Pune", "Mumbai", "Delhi"],
"Amount": [620, 340, 480, 710, 590, 900, 250, 460, 500]
})
step1 = df[df["Amount"] > 500]
result = step1.groupby("City")["Amount"].mean()
print(result["Delhi"])
```
What value gets printed?
₹760.00, the average of Delhi's two transactions that remain after the >500 filter removes ₹480 and ₹500
₹625.00, the average of all four Delhi transactions, as if groupby recomputed on the full DataFrame regardless of the earlier filter
₹673.33, the average of Delhi's ₹620, ₹900, and ₹500, treating the boundary value ₹500 as if it passed the filter
₹705.00, the average of all four filtered transactions across every city, as if groupby merged them into one combined mean
Answer: A. ₹760.00, the average of Delhi's two transactions that remain after the >500 filter removes ₹480 and ₹500
ExplanationFiltering with `df[df["Amount"] > 500]` uses a strict inequality, so it keeps only rows where Amount exceeds 500 — it drops Delhi's ₹480 row and, just as importantly, also drops the ₹500 row, since 500 is not greater than 500. That leaves four rows: Delhi ₹620, Pune ₹710, Mumbai ₹590, and Delhi ₹900. Only after this filtering does `groupby("City")` split the remaining rows by city and compute a separate mean for each group — Mumbai's group has just ₹590, Pune's has just ₹710, and Delhi's group has ₹620 and ₹900, averaging to (620 + 900) / 2 = ₹760.00. The remaining values come from skipping a step in this two-stage pipeline: averaging all four original Delhi rows ignores that the filter runs before the grouping; including ₹500 confuses the strict ">" with ">="; and averaging all four filtered rows together ignores that groupby splits the data into separate per-city groups before each mean is computed.
Question 117 · Inheritance and Polymorphism Deep Dive · hard
A ride-booking startup in Bengaluru models its fleet with this class hierarchy. Trace the code carefully — pay attention to which class's version of each method actually runs when it is called through `self`, and which class `super()` resolves to at each level.
```python
class Vehicle:
def fare(self, distance):
return distance * 10
def surcharge(self, base):
return 0
def book(self, distance):
base = self.fare(distance)
return base + self.surcharge(base)
class Auto(Vehicle):
def surcharge(self, base):
return base * 0.05
class Cab(Auto):
def fare(self, distance):
return distance * 15
def surcharge(self, base):
return super().surcharge(base) + 20
fleet = [Vehicle(), Auto(), Cab()]
total = 0
for ride in fleet:
total += ride.book(10)
print(total)
```
What does this program print as the combined booking total (in rupees) for a 10 km ride on each vehicle in the fleet?
382.5
300.0
375.0
The code raises an AttributeError while computing the Auto instance's fare, because Auto never defines its own fare() method
Answer: A. 382.5
Explanation`book()` is defined once in `Vehicle`, but every call it makes through `self` — `self.fare(...)` and `self.surcharge(...)` — is resolved dynamically against the actual object's class, not the class where `book()` happens to live. This is the core idea of polymorphism: the same inherited method body produces different behaviour depending on which subclass instance calls it.
For the `Vehicle` instance: `fare(10)` is Vehicle's own, giving `10*10 = 100`; `surcharge(100)` is also Vehicle's own, giving `0`. Booking total = `100 + 0 = 100`.
For the `Auto` instance: `Auto` doesn't override `fare`, so Python walks up the MRO to `Vehicle.fare`, giving `100` again. But `surcharge` IS overridden in `Auto`, so `self.surcharge(100)` runs `Auto`'s version: `100 * 0.05 = 5.0`. Booking total = `100 + 5.0 = 105.0`.
For the `Cab` instance: `Cab` overrides `fare`, so `self.fare(10)` runs `Cab`'s version: `10*15 = 150`. Then `self.surcharge(150)` runs `Cab`'s `surcharge`, which calls `super().surcharge(150)`. `Cab`'s MRO is `Cab -> Auto -> Vehicle -> object`, so `super()` inside `Cab` resolves to the *next* class in that chain — `Auto`, not `Vehicle`. That gives `150 * 0.05 = 7.5`, and `Cab.surcharge` adds its own flat `+20`, totalling `7.5 + 20 = 27.5`. Booking total = `150 + 27.5 = 177.5`.
Grand total: `100 + 105.0 + 177.5 = 382.5`.
The distractor of ₹300.0 comes from assuming that because `book()` is written inside `Vehicle`, its internal `self.fare`/`self.surcharge` calls must always run `Vehicle`'s own versions — that would make every vehicle behave identically (`100 + 0 = 100` each), which defeats the entire purpose of overriding methods. The distractor of ₹375.0 comes from assuming `super()` always jumps straight to the topmost ancestor class (`Vehicle`) rather than to the next class in the MRO (`Auto`); that would make `Cab.surcharge = 0 + 20 = 20`, giving a Cab total of `170` instead of `177.5`. The AttributeError distractor comes from assuming a subclass must explicitly redefine every method it wants to use — in reality, `Auto` inherits `fare()` unchanged from `Vehicle` simply by not overriding it, and calling it works exactly as inheritance is meant to.
Question 118 · Python Dataclasses and Type Hints · hard
A CBSE Class 9 coding club uses this dataclass to store student records:
```python
from dataclasses import dataclass, field
@dataclass
class Student:
name: str
marks: list[int] = field(default_factory=list)
s1 = Student("Aditi")
s2 = Student("Rohan")
s1.marks.append(85)
print(s1.marks, s2.marks)
```
This prints `[85] []`, exactly as intended — each `Student` gets its own independent marks list. Now suppose a classmate "simplifies" the field by writing `marks: list[int] = []` directly, deleting `field(default_factory=list)` entirely, and runs the same file. What actually happens?
The code raises a ValueError as soon as the class body is executed, because @dataclass explicitly rejects a bare mutable object like [] as a default and requires field(default_factory=list) instead
The code runs identically to the original, because Python's dataclass module silently rewrites any list literal default into an internal default_factory call behind the scenes
Both s1.marks and s2.marks end up bound to the very same list object, so calling s1.marks.append(85) would also make s2.marks show [85]
Since field() is no longer used, marks silently becomes None for every new Student, and s1.marks.append(85) then raises an AttributeError because None has no append method
Answer: A. The code raises a ValueError as soon as the class body is executed, because @dataclass explicitly rejects a bare mutable object like [] as a default and requires field(default_factory=list) instead
ExplanationPython's dataclass machinery scans every field's default value while the class body is being built, and it specifically checks whether that default is a mutable object such as a list, dict, or set. The moment it sees `marks: list[int] = []`, it raises `ValueError: mutable default <class 'list'> for field marks is not allowed: use default_factory` — right when the class is defined, before `s1 = Student("Aditi")` or `s2 = Student("Rohan")` ever executes, so no Student object is ever created and no append happens at all. This guard exists precisely to prevent the trap the shared-list option describes: in an ordinary Python function, `def f(marks=[]):` really does create the list once at function-definition time and reuse that same object on every call, silently corrupting data across calls until someone hunts down the bug. `@dataclass` shuts that exact mistake down at the class level by refusing a bare mutable literal as a default, forcing you to write `field(default_factory=list)` instead — which tells it "call list() fresh for every new instance" rather than "reuse this one list forever." Type hints like `list[int]` only document what the field is meant to hold; Python does not enforce them at runtime, so they play no role in triggering or preventing this check, and marks is never quietly replaced by None here.
Question 119 · Recurrent Neural Networks and Sequences · hard
A bank's fraud-alert bot for UPI transactions uses a simplified recurrent neural network to build a "risk memory" as it reads a customer's last four transaction amounts (in hundreds of rupees) one at a time, in order. The hidden state update rule is h_t = 0.5 × h_(t-1) + x_t, starting from h_0 = 0. For the transaction sequence ₹800, ₹400, ₹200, ₹600 (so x1=8, x2=4, x3=2, x4=6, in hundreds), what is the final hidden state h4, and what does the calculation reveal about how a vanilla RNN treats the four transactions?
h4 = 9; because each earlier transaction's contribution is repeatedly halved by later steps, the RNN's final memory is dominated by the most recent transactions rather than being a plain total
h4 = 20; the hidden state equals the plain sum of all four transaction amounts, since a recurrent cell simply accumulates every input it has seen with no memory decay
h4 = 10; the decay factor multiplies each new incoming transaction before it is added, giving h_t = h_(t-1) + 0.5x_t, so every transaction ends up with equal long-term weight in the final state
h4 = 5; the hidden state is just the average of the four transaction amounts, so an RNN processing a sequence is equivalent to a plain unweighted average of its inputs
Answer: A. h4 = 9; because each earlier transaction's contribution is repeatedly halved by later steps, the RNN's final memory is dominated by the most recent transactions rather than being a plain total
ExplanationApplying h_t = 0.5h_(t-1) + x_t step by step from h_0 = 0: h_1 = 0.5(0) + 8 = 8, h_2 = 0.5(8) + 4 = 8, h_3 = 0.5(8) + 2 = 6, h_4 = 0.5(6) + 6 = 9. Unfolding the recursion confirms this: h_4 = 0.5³(8) + 0.5²(4) + 0.5¹(2) + 0.5⁰(6) = 1 + 1 + 1 + 6 = 9. The earliest transaction (₹800) is shrunk by a factor of 0.5³ = 0.125 by the time it reaches the final state, while the most recent transaction (₹600) is added at full strength and untouched by any decay. This recency-weighting — not a plain running total (which would ignore the 0.5 decay entirely) and not a flat average (which would treat all four transactions as equally important) — is exactly the behaviour that makes vanilla RNNs good at picking up short-range patterns but prone to "forgetting" distant inputs. This vanishing-influence problem is the core motivation for gated architectures like LSTMs and GRUs when a model needs to remember longer transaction histories.
Question 120 · Recommendation Systems: How Netflix, Spotify, and Flipkart Know What You Want · hard
Netflix's recommendation engine often measures how alike two viewers' tastes are using cosine similarity: it treats each viewer's star ratings as a vector and compares the *direction* of the vectors (the pattern of relative preference), not just the raw numbers, using cos(θ) = (A·B) / (|A|×|B|). Priya and Karan have both watched and rated two movies: Priya gave Dangal 3 stars and KGF 4 stars, while Karan gave Dangal 4 stars and KGF 3 stars. What is the cosine similarity between Priya's and Karan's rating vectors?
0.96, since the dot product is 24 and both vectors have magnitude 5, giving 24 divided by (5 times 5).
24, since that is the dot product of Priya's and Karan's rating vectors, taken as the similarity score directly.
Approximately 0.49, if magnitude is calculated by adding the ratings (3+4=7 and 4+3=7) instead of using the square root of the sum of squares.
0.75, since for each movie the smaller rating divided by the larger rating is 3/4, and averaging 3/4 and 3/4 gives 0.75.
Answer: A. 0.96, since the dot product is 24 and both vectors have magnitude 5, giving 24 divided by (5 times 5).
ExplanationTreat each user's ratings as a vector over (Dangal, KGF): Priya = (3, 4) and Karan = (4, 3). The dot product is (3×4) + (4×3) = 12 + 12 = 24. Each vector's magnitude comes from the Pythagorean theorem — the square root of the sum of squares: √(3²+4²) = √25 = 5 for Priya, and √(4²+3²) = √25 = 5 for Karan. Cosine similarity divides the dot product by the product of the magnitudes: 24 ÷ (5 × 5) = 24/25 = 0.96. A value this close to 1 tells the recommender that Priya's and Karan's tastes point in nearly the same direction, even though neither rated the two movies identically — so a movie Karan loved that Priya hasn't watched yet, such as RRR, becomes a strong recommendation for her. The raw dot product (24) by itself is not a valid similarity score because it isn't normalised: a viewer who rated everything 5 stars would produce a huge dot product with almost anyone simply because their numbers are large, not because their taste actually matches. Dividing by both magnitudes cancels out this scale effect. Computing magnitude by summing the ratings (3+4=7) instead of squaring and taking the square root skips the Pythagorean geometry the formula depends on, and averaging the smaller-to-larger rating ratios per movie is a plausible-sounding shortcut but ignores how the vectors relate to each other as a whole. This normalised, direction-based comparison is exactly why cosine similarity — not raw dot products or per-item ratios — is the standard tool behind collaborative filtering on platforms like Netflix, Spotify, and Flipkart.