Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

12 Core Algorithmic Patterns & 168 Practice Problems

  • 1. Two Pointers (9 Paradigms, 32 Problems): Converging pointers, sorted pair sums, container with most water, trapping rain water, 3Sum, plus the Sliding Window and Fast & Slow Pointers paradigms (Floyd cycle detection, monotonic window invariants, longest substrings, minimum window).
  • 2. Binary Search (8 Paradigms, 12 Problems): Monotonic predicate partitioning, boundary searching, rotated arrays, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 8 Problems): Bitmasking, XOR tricks, counting set bits, subset enumeration via bitmasks.
  • 4. Math & Geometry (5 Paradigms, 10 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (8 Paradigms, 17 Problems): Path sums, lowest common ancestor, tree diameter, subtree serialization, validating BSTs.
  • 6. Tree/Graph Breadth-First Search (4 Paradigms, 11 Problems): Level-order traversals, shortest path, rotting oranges, word ladders.
  • 7. Graphs (6 Paradigms, 14 Problems): Topological sort, cycle detection, Dijkstra, bipartite validation, network delay.
  • 8. Backtracking (5 Paradigms, 13 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens.
  • 9. Dynamic Programming (7 Paradigms, 14 Problems): Memoization vs tabulation, knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (8 Paradigms, 10 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (5 Paradigms, 13 Problems): Trie, Union-Find, LRU Cache, LFU Cache, Monotonic Stacks.
  • 12. Intervals & Stack / Miscellaneous (7 Paradigms, 14 Problems): Merge intervals, daily temperatures, largest rectangle in histogram, trapping rain water via stack.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Multi-language Rosetta Stone contrasting abstract invariants with concrete solutions across Python, C#, Java, TypeScript, C++, Go, and Rust.
  2. Stage 2 (Active Recall): Reconstruct algorithmic template invariants from memory with real-time feedback before looking at solutions.
  3. Stage 3 (Senior SWE AI Mock Coach): Simulated senior mock interview evaluating Big-O space/time tradeoffs, edge cases, and code reviews in Monaco Editor.
  4. Stage 4 (Solve on Your Own): Timed sandbox challenges verified against automated test suites in Python, C#, Java, and TypeScript.

Equipped with SM-2 Spaced Repetition Review Hub, Studio Cockpit workspace layout, and interactive study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Compute Coins: 40 free coins upon signup, +20 daily login bonus, +25 referral bonus.
  • 24-Hour AI Coaching Pass: 5 compute coins unlocks unlimited senior SWE AI coaching for a full 24 hours.
  • BYOK (Bring Your Own Key): Completely free unlimited AI coaching if using your own Gemini/OpenAI API key.
  • Refund & Subscription Policy: No recurring charges, no subscription traps, and no paid paywalls. Free tier provides full learning path.
  • Platform Operator: Hi👋WebEnterprise Inc. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

180Items
Theory Context•Advanced Data Structures
MediumLC 307

Range Sum Query - Mutable (LeetCode 307)

You will see how a segment tree answers range sums and point updates in O(log N) by storing the sum of every half-range.

Target Frequency:GoogleAmazonMeta

You get an integer array nums, followed by a mix of two kinds of requests in any order: change one element, or report the sum of a contiguous stretch of elements.

Build the NumArray class:

  • NumArray(nums) stores the array.
  • update(index, val) sets nums[index] to val.
  • sumRange(left, right) returns nums[left] + nums[left + 1] + ... + nums[right], both ends included (left <= right).

Worked Examples

Example 1
Input:["NumArray", "sumRange", "update", "sumRange"] [[[1, 3, 5]], [0, 2], [1, 2], [0, 2]]
Output:[null, 9, null, 8]
103152update(1, 2)
Explanation: The array starts as `[1, 3, 5]`, so `sumRange(0, 2)` is `1 + 3 + 5 = 9`. `update(1, 2)` makes it `[1, 2, 5]`, and the next `sumRange(0, 2)` is `1 + 2 + 5 = 8`.

⚖️Formal Constraints & Bounds

  • 1 <= nums.length <= 3 * 104

  • -100 <= nums[i] <= 100

  • 0 <= index < nums.length

  • -100 <= val <= 100

  • 0 <= left <= right < nums.length

  • At most 3 * 104 calls will be made to update and sumRange.

Deep-Dive & Conceptual Insights

Why It Works & Core Invariant

Store the sum of every range the recursive halving creates: a query range is covered by O(log N) stored nodes, and a changed element only affects the O(log N) nodes on its root path.

Real-World Scenario & Production Applications

Live dashboards and leaderboards that keep running totals while individual values keep changing: bucketed counters (requests per second, sales per day) where a single bucket is corrected and a range total is read on every page load. A plain prefix array would need an O(N) rebuild after every change.

Step-by-Step Execution Trace Table

nums = [1, 3, 5]. Nodes: 0 = [0..2], 1 = [0..1], 2 = [2..2], 3 = [0..0], 4 = [1..1].

CallNodes visitedWhat happenstree[0..4] afterReturns
build3, 4, 1, 2, 0leaves 1, 3, 5; node 1 = 1 + 3; node 0 = 4 + 5[9, 4, 5, 1, 3]
sumRange(0, 2)0node 0 covers [0..2], fully inside: stored sumunchanged9
update(1, 2)0 → 1 → 4, back up 1, 0leaf 4 = 2; recompute node 1 = 1 + 2 = 3; node 0 = 3 + 5 = 8[8, 3, 5, 1, 2]null
sumRange(0, 2)0fully inside againunchanged8
Scroll horizontally to see all columns, or expand to full screen
Core Invariant Specification & Code Shape
Archetype Code Shape
Python
1Every node stores the sum of a range, and its two children store the two halves, so a range is a few stored nodes and a change touches one path.
2After every `update`, `self.tree[node]` equals the sum of `nums[left..right]` for its range; `query` returns the stored sum when fully inside, `0` when fully outside, and splits otherwise.
3`_build(nums, 0, 0, n - 1)` recursively; `update(index, val)` goes left if `index <= mid` else right, then recomputes; `query(ql, qr)` combines both halves; `NumArray` forwards the calls.
4The trap: after the recursive `update` returns, recompute `self.tree[node] = self.tree[2 * node + 1] + self.tree[2 * node + 2]`, or every sum above the leaf stays stale.

Target: Range Sum Query - Mutable (LeetCode 307). 4n slots always fit the tree, whatever n is.

Boundary Model: Trie Prefix Tree Branching / DSU Near-Flat Forest

Trie: root-to-node path encodes common prefix; DSU: find(u) with path compression flattens tree so root is direct parent.

Loop Invariant Termination

Trie: traverse word char-by-char in O(L); DSU: if find(u) != find(v): union(u, v) in O(alpha(N)).

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

A segment tree stores the answer for a range in every node: the root covers the whole array, its two children cover the two halves, and so on down to single elements. Any query range [ql, qr] splits into a few stored nodes (about two per level), and changing one element only touches the nodes on the path from its leaf to the root. Both operations are O(log⁡N)O(\log N)O(logN), and unlike a Fenwick tree the same shape works for max, min or any operation that combines two halves.

🏟️ The Analogy: Regional Sales Reports

A company files sales by store, then by city, then by region, then for the whole country, each report adding up the ones below it. To answer "sales in these twelve neighbouring stores" you pick a couple of city reports that sit fully inside the range plus a few stores at the edges. When one store corrects its number, only its city, its region and the country report need a new total.

🪄 The Mathematical Harmony / Magic Trick
Code / Blueprint
def query(self, ql, qr, node, left, right):
if ql <= left and right <= qr:
return self.tree[node] # fully inside: stored sum
if right < ql or left > qr:
return 0 # fully outside: neutral value
mid = (left + right) // 2 # partial: ask both halves
return self.query(ql, qr, 2 * node + 1, left, mid) + self.query(ql, qr, 2 * node + 2, mid + 1, right)
 

update walks down to the leaf for index, overwrites it with val, and on the way back up sets self.tree[node] = self.tree[2 * node + 1] + self.tree[2 * node + 2] for every ancestor. That recompute is what keeps every stored sum true.

💡 Summary

Node i covers [left, right], its children 2i + 1 and 2i + 2 cover the halves; 4 * n slots are always enough. Build is O(N)O(N)O(N), and each update or query is O(log⁡N)O(\log N)O(logN). NumArray passes every call straight through: update sets the value (no difference needed), sumRange is query(left, right).

  • Not recomputing ancestors: changing only the leaf in update leaves every sum above it stale; on [1,3,5], update(1, 2) then sumRange(0, 2) would still return 9. Recompute self.tree[node] after the recursive call returns.

  • Too little space: 2 * n slots overflow when n is not a power of two; allocate 4 * n.

  • Wrong neutral value: a node fully outside the query must return 0 for sums (it would be -inf for max, inf for min).

  • Adding instead of overwriting: the segment tree stores values, so update sets the leaf to val; adding val (Fenwick style) double-counts the old value.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

You will see how a senior engineer picks a segment tree and explains why updates must recompute on the way up.

Pattern Recognition Signals

The 10-second spot

"Change one element" mixed with "sum of a contiguous stretch", many times and in any order: every call must be fast, not just the reads. A Segment Tree gives O(log N) for both, and the same structure would also handle range max or min if the question changed.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

After every update, self.tree[node] equals the sum of nums[left..right] for the range that node covers; query uses a node's stored sum only when the node lies fully inside [ql, qr].

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • self.tree[node] = self.tree[2 * node + 1] + self.tree[2 * node + 2] after the recursive update: changing only the leaf leaves every sum above it stale.

  • self.tree = [0] * (4 * self.n): 2 * n overflows when n is not a power of two.

  • return 0 for a node fully outside the query: the neutral value for sum.

  • self.tree[node] = val at the leaf: overwrite, don't add.

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use a Segment Tree. Each node stores the sum of a range: the root covers the whole array and each node's two children cover its two halves. For a sum query, a node fully inside the range returns its stored sum, a node fully outside returns zero, and a partly covered node asks both children; that touches about two nodes per level, so O(log N). For an update, I walk down to the leaf for that index, overwrite it with the new value, and on the way back up recompute each ancestor as the sum of its two children. That recompute is the trap: skip it and every sum above the leaf goes stale. Building the tree is O(N), each update and query is O(log N), and it takes O(N) space with four times n slots.

So: fully inside, fully outside, or split; overwrite the leaf, then recompute every ancestor.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N) build, O(log N) query & update

Look at the recursion: _build visits each node once, and the tree has 2N - 1 nodes, so build is O(N). update follows one path from the root to a leaf (depth about log2 N) and does O(1) work per node on the way back up: O(log N). query stops at nodes fully inside or fully outside; at each level at most two nodes are partly covered, so it visits O(log N) nodes.

SPACE COMPLEXITY

O(N)

self.tree has 4 * n slots: O(N). The recursion is at most about log2 N + 1 calls deep, which is O(log N) of call stack.

Formal Recurrence Relation

T(build)=O(2N−1)=O(N);T(update)=T(query)=O(log⁡N)T(build) = O(2N - 1) = O(N); T(update) = T(query) = O(\log N)T(build)=O(2N−1)=O(N);T(update)=T(query)=O(logN)

Look at the recursion: _build visits each node once, and the tree has 2N - 1 nodes, so build is O(N). update follows one path from the root to a leaf (depth about log2 N) and does O(1) work per node on the way back up: O(log N). query stops at nodes fully inside or fully outside; at each level at most two nodes are partly covered, so it visits O(log N) nodes.

Derivation Progression

Build

2N - 1 nodes × O(1)

_build creates every leaf and combines every internal node once.

Update

depth × O(1) = O(log N)

One root-to-leaf path down, one recompute per ancestor on the way up.

Query

≤ 2 partial nodes per level = O(log N)

Fully inside or fully outside nodes stop the recursion immediately.

Variable Definitions

NNN

Length of nums

nodenodenode

A tree slot; its children are 2 * node + 1 and 2 * node + 2

Memory Architecture & Bounds

🟣 Call Stack

O(log N): recursion depth of update, query and _build

🔵 Auxiliary Heap

O(N): self.tree with 4n slots

🟢 Output Space

O(1) per call

Boundary Best / Worst Cases

Best Case

O(1)O(1)O(1) for a query that covers the whole array (the root answers it)

Average Case

O(log⁡N)O(\log N)O(logN) per operation; O(N)O(N)O(N) to build

Worst Case

O(log⁡N)O(\log N)O(logN) per update and query

Recurrence Tree Topology

Recurrence Tree Topology
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "change one element", "sum of a contiguous stretch", "in any order". Updates and range queries interleaved: a Segment Tree (it also covers max/min/other combine operations, where a Fenwick tree does not).

CONSTRAINTS & BOUNDS

N≤3×104N \le 3 \times 10^4N≤3×104 and at most 3×1043 \times 10^43×104 calls: about 16 levels, so each call visits a few dozen nodes. 4N4N4N slots is about 1.2×1051.2 \times 10^51.2×105 integers.

FAANG PRODUCTION TRAPS & EDGE CASES

Forgetting the recompute leaves stale sums. Recursion depth is only about log2 N, but in a service the array often lives longer than one request: rebuild in O(N) after bulk loads instead of N separate updates.

Core Algorithmic State Invariants

1. Node Sum Invariant

After every `update`, `self.tree[node]` equals the sum of `nums[left..right]` for the range the node covers; children `2 * node + 1` and `2 * node + 2` cover the two halves.

2. Inside, Outside, Split

`query` returns the stored sum for a node fully inside `[ql, qr]`, `0` for a node fully outside, and asks both children otherwise; `update` recomputes each ancestor after its child changes.

3. Log-Depth Paths

Build touches 2N - 1 nodes (O(N)); update follows one root-to-leaf path and query at most two partial nodes per level: O(log N) each, with 4n slots of space.

Theory Context•Advanced Data Structures
MediumLC 307

Range Sum Query - Mutable (LeetCode 307)

You will see how a segment tree answers range sums and point updates in O(log N) by storing the sum of every half-range.

Target Frequency:GoogleAmazonMeta

You get an integer array nums, followed by a mix of two kinds of requests in any order: change one element, or report the sum of a contiguous stretch of elements.

Build the NumArray class:

  • NumArray(nums) stores the array.
  • update(index, val) sets nums[index] to val.
  • sumRange(left, right) returns nums[left] + nums[left + 1] + ... + nums[right], both ends included (left <= right).

Worked Examples

Example 1
Input:["NumArray", "sumRange", "update", "sumRange"] [[[1, 3, 5]], [0, 2], [1, 2], [0, 2]]
Output:[null, 9, null, 8]
103152update(1, 2)
Explanation: The array starts as `[1, 3, 5]`, so `sumRange(0, 2)` is `1 + 3 + 5 = 9`. `update(1, 2)` makes it `[1, 2, 5]`, and the next `sumRange(0, 2)` is `1 + 2 + 5 = 8`.

⚖️Formal Constraints & Bounds

  • 1 <= nums.length <= 3 * 104

  • -100 <= nums[i] <= 100

  • 0 <= index < nums.length

  • -100 <= val <= 100

  • 0 <= left <= right < nums.length

  • At most 3 * 104 calls will be made to update and sumRange.

Deep-Dive & Conceptual Insights

Why It Works & Core Invariant

Store the sum of every range the recursive halving creates: a query range is covered by O(log N) stored nodes, and a changed element only affects the O(log N) nodes on its root path.

Real-World Scenario & Production Applications

Live dashboards and leaderboards that keep running totals while individual values keep changing: bucketed counters (requests per second, sales per day) where a single bucket is corrected and a range total is read on every page load. A plain prefix array would need an O(N) rebuild after every change.

Step-by-Step Execution Trace Table

nums = [1, 3, 5]. Nodes: 0 = [0..2], 1 = [0..1], 2 = [2..2], 3 = [0..0], 4 = [1..1].

CallNodes visitedWhat happenstree[0..4] afterReturns
build3, 4, 1, 2, 0leaves 1, 3, 5; node 1 = 1 + 3; node 0 = 4 + 5[9, 4, 5, 1, 3]
sumRange(0, 2)0node 0 covers [0..2], fully inside: stored sumunchanged9
update(1, 2)0 → 1 → 4, back up 1, 0leaf 4 = 2; recompute node 1 = 1 + 2 = 3; node 0 = 3 + 5 = 8[8, 3, 5, 1, 2]null
sumRange(0, 2)0fully inside againunchanged8
Scroll horizontally to see all columns, or expand to full screen
Core Invariant Specification & Code Shape
Archetype Code Shape
Python
1Every node stores the sum of a range, and its two children store the two halves, so a range is a few stored nodes and a change touches one path.
2After every `update`, `self.tree[node]` equals the sum of `nums[left..right]` for its range; `query` returns the stored sum when fully inside, `0` when fully outside, and splits otherwise.
3`_build(nums, 0, 0, n - 1)` recursively; `update(index, val)` goes left if `index <= mid` else right, then recomputes; `query(ql, qr)` combines both halves; `NumArray` forwards the calls.
4The trap: after the recursive `update` returns, recompute `self.tree[node] = self.tree[2 * node + 1] + self.tree[2 * node + 2]`, or every sum above the leaf stays stale.

Target: Range Sum Query - Mutable (LeetCode 307). 4n slots always fit the tree, whatever n is.

Boundary Model: Trie Prefix Tree Branching / DSU Near-Flat Forest

Trie: root-to-node path encodes common prefix; DSU: find(u) with path compression flattens tree so root is direct parent.

Loop Invariant Termination

Trie: traverse word char-by-char in O(L); DSU: if find(u) != find(v): union(u, v) in O(alpha(N)).

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

A segment tree stores the answer for a range in every node: the root covers the whole array, its two children cover the two halves, and so on down to single elements. Any query range [ql, qr] splits into a few stored nodes (about two per level), and changing one element only touches the nodes on the path from its leaf to the root. Both operations are O(log⁡N)O(\log N)O(logN), and unlike a Fenwick tree the same shape works for max, min or any operation that combines two halves.

🏟️ The Analogy: Regional Sales Reports

A company files sales by store, then by city, then by region, then for the whole country, each report adding up the ones below it. To answer "sales in these twelve neighbouring stores" you pick a couple of city reports that sit fully inside the range plus a few stores at the edges. When one store corrects its number, only its city, its region and the country report need a new total.

🪄 The Mathematical Harmony / Magic Trick
Code / Blueprint
def query(self, ql, qr, node, left, right):
if ql <= left and right <= qr:
return self.tree[node] # fully inside: stored sum
if right < ql or left > qr:
return 0 # fully outside: neutral value
mid = (left + right) // 2 # partial: ask both halves
return self.query(ql, qr, 2 * node + 1, left, mid) + self.query(ql, qr, 2 * node + 2, mid + 1, right)
 

update walks down to the leaf for index, overwrites it with val, and on the way back up sets self.tree[node] = self.tree[2 * node + 1] + self.tree[2 * node + 2] for every ancestor. That recompute is what keeps every stored sum true.

💡 Summary

Node i covers [left, right], its children 2i + 1 and 2i + 2 cover the halves; 4 * n slots are always enough. Build is O(N)O(N)O(N), and each update or query is O(log⁡N)O(\log N)O(logN). NumArray passes every call straight through: update sets the value (no difference needed), sumRange is query(left, right).

  • Not recomputing ancestors: changing only the leaf in update leaves every sum above it stale; on [1,3,5], update(1, 2) then sumRange(0, 2) would still return 9. Recompute self.tree[node] after the recursive call returns.

  • Too little space: 2 * n slots overflow when n is not a power of two; allocate 4 * n.

  • Wrong neutral value: a node fully outside the query must return 0 for sums (it would be -inf for max, inf for min).

  • Adding instead of overwriting: the segment tree stores values, so update sets the leaf to val; adding val (Fenwick style) double-counts the old value.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

You will see how a senior engineer picks a segment tree and explains why updates must recompute on the way up.

Pattern Recognition Signals

The 10-second spot

"Change one element" mixed with "sum of a contiguous stretch", many times and in any order: every call must be fast, not just the reads. A Segment Tree gives O(log N) for both, and the same structure would also handle range max or min if the question changed.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

After every update, self.tree[node] equals the sum of nums[left..right] for the range that node covers; query uses a node's stored sum only when the node lies fully inside [ql, qr].

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • self.tree[node] = self.tree[2 * node + 1] + self.tree[2 * node + 2] after the recursive update: changing only the leaf leaves every sum above it stale.

  • self.tree = [0] * (4 * self.n): 2 * n overflows when n is not a power of two.

  • return 0 for a node fully outside the query: the neutral value for sum.

  • self.tree[node] = val at the leaf: overwrite, don't add.

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use a Segment Tree. Each node stores the sum of a range: the root covers the whole array and each node's two children cover its two halves. For a sum query, a node fully inside the range returns its stored sum, a node fully outside returns zero, and a partly covered node asks both children; that touches about two nodes per level, so O(log N). For an update, I walk down to the leaf for that index, overwrite it with the new value, and on the way back up recompute each ancestor as the sum of its two children. That recompute is the trap: skip it and every sum above the leaf goes stale. Building the tree is O(N), each update and query is O(log N), and it takes O(N) space with four times n slots.

So: fully inside, fully outside, or split; overwrite the leaf, then recompute every ancestor.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N) build, O(log N) query & update

Look at the recursion: _build visits each node once, and the tree has 2N - 1 nodes, so build is O(N). update follows one path from the root to a leaf (depth about log2 N) and does O(1) work per node on the way back up: O(log N). query stops at nodes fully inside or fully outside; at each level at most two nodes are partly covered, so it visits O(log N) nodes.

SPACE COMPLEXITY

O(N)

self.tree has 4 * n slots: O(N). The recursion is at most about log2 N + 1 calls deep, which is O(log N) of call stack.

Formal Recurrence Relation

T(build)=O(2N−1)=O(N);T(update)=T(query)=O(log⁡N)T(build) = O(2N - 1) = O(N); T(update) = T(query) = O(\log N)T(build)=O(2N−1)=O(N);T(update)=T(query)=O(logN)

Look at the recursion: _build visits each node once, and the tree has 2N - 1 nodes, so build is O(N). update follows one path from the root to a leaf (depth about log2 N) and does O(1) work per node on the way back up: O(log N). query stops at nodes fully inside or fully outside; at each level at most two nodes are partly covered, so it visits O(log N) nodes.

Derivation Progression

Build

2N - 1 nodes × O(1)

_build creates every leaf and combines every internal node once.

Update

depth × O(1) = O(log N)

One root-to-leaf path down, one recompute per ancestor on the way up.

Query

≤ 2 partial nodes per level = O(log N)

Fully inside or fully outside nodes stop the recursion immediately.

Variable Definitions

NNN

Length of nums

nodenodenode

A tree slot; its children are 2 * node + 1 and 2 * node + 2

Memory Architecture & Bounds

🟣 Call Stack

O(log N): recursion depth of update, query and _build

🔵 Auxiliary Heap

O(N): self.tree with 4n slots

🟢 Output Space

O(1) per call

Boundary Best / Worst Cases

Best Case

O(1)O(1)O(1) for a query that covers the whole array (the root answers it)

Average Case

O(log⁡N)O(\log N)O(logN) per operation; O(N)O(N)O(N) to build

Worst Case

O(log⁡N)O(\log N)O(logN) per update and query

Recurrence Tree Topology

Recurrence Tree Topology
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "change one element", "sum of a contiguous stretch", "in any order". Updates and range queries interleaved: a Segment Tree (it also covers max/min/other combine operations, where a Fenwick tree does not).

CONSTRAINTS & BOUNDS

N≤3×104N \le 3 \times 10^4N≤3×104 and at most 3×1043 \times 10^43×104 calls: about 16 levels, so each call visits a few dozen nodes. 4N4N4N slots is about 1.2×1051.2 \times 10^51.2×105 integers.

FAANG PRODUCTION TRAPS & EDGE CASES

Forgetting the recompute leaves stale sums. Recursion depth is only about log2 N, but in a service the array often lives longer than one request: rebuild in O(N) after bulk loads instead of N separate updates.

Core Algorithmic State Invariants

1. Node Sum Invariant

After every `update`, `self.tree[node]` equals the sum of `nums[left..right]` for the range the node covers; children `2 * node + 1` and `2 * node + 2` cover the two halves.

2. Inside, Outside, Split

`query` returns the stored sum for a node fully inside `[ql, qr]`, `0` for a node fully outside, and asks both children otherwise; `update` recomputes each ancestor after its child changes.

3. Log-Depth Paths

Build touches 2N - 1 nodes (O(N)); update follows one root-to-leaf path and query at most two partial nodes per level: O(log N) each, with 4n slots of space.

Rosetta Dual-Monaco Comparison
Python 3
CANONICAL INVARIANT TEMPLATE
Loading...
CONCRETE: RANGE SUM QUERY - MUTABLE (LEETCODE 307)
T = O(N) build, O(log N) query & updateS = O(N)
Loading...
Pattern Implementation Mapping TableCanonical Invariant ⟷ Concrete Code ⟷ Engineering Rationale
Canonical InvariantConcrete CodeEngineering Rationale
Node i covers [left, right]; children 2i+1 and 2i+2 cover the halvesself.tree = [0] * (4 * self.n)4n slots always fit the tree, whatever n is.
Build bottom-up: leaves, then combine childrenself.tree[node] = self.tree[2 * node + 1] + self.tree[2 * node + 2]Every internal node stores the sum of its two halves.
Point update: go down to the leaf, overwrite itif left == right: self.tree[node] = valThe leaf for index holds exactly nums[index], so it is simply replaced.
Recompute ancestors on the way back upself.tree[node] = self.tree[2 * node + 1] + self.tree[2 * node + 2] # Recompute on the way upWithout it, every sum above the changed leaf is stale.
Query: fully inside, fully outside, or splitif ql <= left and right <= qr: return self.tree[node] if right < ql or left > qr: return 0Fully inside uses the stored sum; fully outside adds the neutral value 0; otherwise ask both halves.
NumArray passes calls straight throughself.seg.update(index, val) return self.seg.query(left, right)The tree overwrites leaves, so no difference is needed, and query takes LeetCode's 0-indexed range directly.
© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•