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).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Dynamic Programming

Builds on Kadane's Algorithm, which you haven’t finished yet.

P1MediumBuilt on Linear DP~4 min speedrun

Kadane's Algorithm with a Product (Maximum Product Subarray)

Built on
Kadane's AlgorithmA negative number turns the smallest product into the largest, so keep both hi and lo, the largest and smallest product of a subarray that ends here.
The problem

Maximum Product Subarray (LC 152)(opens leetcode.com)

You get an integer array nums. A subarray is a run of numbers that sit next to each other. Multiply the numbers of a subarray to get its product.

Find the subarray with the largest product and return that product. The array can hold negative numbers and zeros. The subarray must hold at least one number.

Example 1
Input:nums = [2,3,-2,4]
Output:6
The subarray [2, 3] has product 6. No other subarray is larger: -2 makes any run that holds it smaller, and [4] is only 4.

Maximum Product Subarray

hi, lo = largest and smallest product ending at x ➔ a negative x swaps their roles ➔ keep the best hi
Spot it when: You need the best product of one unbroken run of an array, and the numbers may be negative or zero.
Maximum Product Subarray
Python
1def max_product(nums: list[int]) -> int:
2 """Maximum Product Subarray: the best product of one unbroken run, found in a single pass.
3 Time: O(N) | Space: O(1)
4 """
5 # hi, lo: the largest and smallest product of a subarray that ends at the current number; best: the largest hi seen so far
6 hi = lo = best = nums[0]
7 for x in nums[1:]:
8 # 1. Try x Alone, hi * x And lo * x:
9 # A negative x turns the smallest product into the largest, so both ends are extended. Both use the old hi and lo.
10 hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x)
11 
12 # 2. Track The Best:
13 # Every subarray ends at some index, so the largest hi seen at any index is the answer.
14 best = max(best, hi)
15 
16 return best
Invariant: Multiplying by a negative number flips the extremes: the biggest product becomes the smallest, and the smallest becomes the biggest. So after each x, keep both the largest and the smallest product: hi is the largest and lo is the smallest product of a subarray that ends at x, and best is the largest hi seen so far.

A negative x turns the smallest product that ends before it into the largest, so keep both ends: hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x). Every subarray that ends at x is x alone or an earlier subarray extended by x, so these three candidates cover all of them, and best keeps the largest hi seen. The trap is the order: compute hi and lo in one assignment from the old values, because if hi changes first, lo is computed from a different subarray.

See it run

Maximum Product Subarray, step by step

hi -2 · lo -2 · best -2

hi -2 · lo -2 · best -2

hi 0 · lo 0 · best 0

hi 0 · lo 0 · best 0

hi 0 · lo -1 · best 0

hi 0 · lo -1 · best 0

hi 3 · lo -3 · best 3

hi 3 · lo -3 · best 3

hi 12 · lo -12 · best 12

hi 12 · lo -12 · best 12

Each column is one index of nums. The rows hi and lo fill in as the steps run.

  • x the number being read
  • hi the largest product of a run that ends at x
  • lo the smallest product of a run that ends at x

Start: hi = lo = best = nums[0] = -2. Only one subarray ends at index 0.

Read x = 0. The candidates are x = 0, hi * x = -2 * 0 = 0, and lo * x = -2 * 0 = 0.

hi = max of the three = 0, and lo = min of the three = 0, so best = 0. The old run keeps growing.

Read x = -1. The candidates are x = -1, hi * x = 0 * -1 = 0, and lo * x = 0 * -1 = 0.

hi = max of the three = 0, and lo = min of the three = -1, so best = 0. The smallest old product times a negative x gave the new hi.

Read x = 3. The candidates are x = 3, hi * x = 0 * 3 = 0, and lo * x = -1 * 3 = -3.

hi = max of the three = 3, and lo = min of the three = -3, so best = 3. x alone is the largest, so a new run starts at x.

Read x = -4. The candidates are x = -4, hi * x = 3 * -4 = -12, and lo * x = -3 * -4 = 12.

hi = max of the three = 12, and lo = min of the three = -12, so best = 12. The smallest old product times a negative x gave the new hi.

Done: best = 12. The loop returns best, because the best run can end before the last number.

nums
0-2x
10
2-1
33
4-4
hi
-2hi
lo
-2lo
1 / 10
Gotchas1 of 3

Gotcha 1 of 3

  1. 1
    The trap

    Gotcha 1: Keeping only the largest product

    Mistake
    curr = max(x, curr * x)
    Fix
    hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x)

    What happens: A negative x turns the smallest product into the largest one. With only the largest product, the smallest product is lost, so a pair of negative numbers never combines into a positive product.

    Example: Maximum Product Subarray (LC 152): nums = [-2, 3, -4]
    Mistake: returns 3Fix: returns 24
  2. 2

    Gotcha 2: Updating hi before computing lo

    Mistake
    hi = max(x, hi * x, lo * x)
    lo = min(x, hi * x, lo * x)
    Fix
    hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x)

    What happens: The second line reads the new hi, which is the largest product ending at x, not the largest product ending before x. hi * x then multiplies x twice, so lo describes a run that does not exist.

    Example: Maximum Product Subarray (LC 152): nums = [-2, -3, -4]
    Mistake: returns 72Fix: returns 12
  3. 3

    Gotcha 3: Leaving x out of the candidates

    Mistake
    hi, lo = max(hi * x, lo * x), min(hi * x, lo * x)
    Fix
    hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x)

    What happens: After a zero, hi and lo are both 0, and hi * x and lo * x stay 0. Only x alone can start a new run. Without it, every product after a zero is 0.

    Example: Maximum Product Subarray (LC 152): nums = [0, 2]
    Mistake: returns 0Fix: returns 2
Not this one if…
  • The best run is a sum, and adding a number never swaps the smallest and the largest, so one running value curr is enough, as in Maximum Subarray (LC 53). See Kadane's Algorithm

Deep Dive

Why the smallest product must be kept

In Kadane's Algorithm, a larger earlier value always gives a larger new value. A product does not follow this rule. Multiplying by a negative x reverses the order: the smallest earlier product becomes the largest new product.

So the state has two values for the subarrays that end at the current number. hi is the largest product and lo is the smallest product. lo is often negative, and one more negative x turns it into the next hi.

Example: for nums = [-2, 3, -4], after 3 the pair is hi = 3 and lo = -6. Then x = -4 gives lo * x = 24. The answer is 24. Without lo, the answer would be 3.

Why three candidates cover every subarray

A subarray that ends at x is x alone, or an earlier subarray that ends just before x, followed by x.

For the second form, the product is p * x, where p is the product of the earlier subarray. If x > 0, the largest result comes from the largest p, which is hi. If x < 0, it comes from the smallest p, which is lo. If x = 0, every result is 0.

So max(x, hi * x, lo * x) is the largest product that ends at x, and min(x, hi * x, lo * x) is the smallest. The tuple assignment computes both from the old hi and lo.

A zero resets the state. After x = 0, both hi and lo are 0. The next number starts a new run through the candidate x alone.

Trace and the cost

Trace for nums = [2, 3, -2, 4], as x, hi, lo, best:

  • 2, 2, 2, 2 (the start).
  • 3, 6, 3, 6.
  • -2, -2, -12, 6.
  • 4, 4, -48, 6.

The answer is 6, from [2, 3]. Trace for nums = [-2, 0, -1, 3, -4]: best is 12, from the run [-1, 3, -4]. The zero ends the earlier run, and the next run starts at -1.

The time is O(N), with three products per number. The space is O(1).

Products grow fast. With 40 copies of 2, the result is 1,099,511,627,776. Python integers have no limit. In a language with 32-bit or 64-bit integers, check the size limit, which LeetCode states for each problem.

Two other ways to the same answer

A second method uses prefix products. Scan from the left with a running product, and again from the right. After a zero, restart the running product at 1. The answer is the largest product seen in either scan. The reason is that the best subarray either has an even number of negative numbers, or it drops a negative number at one end. One of the two scans reaches it. This gives the same results as max_product on random arrays with zeros and negative numbers.

The variant Maximum Length of Subarray With Positive Product (LC 1567) keeps lengths and not products. Keep pos, the longest run ending here with a positive product, and neg, the longest with a negative product. A negative x swaps pos and neg, and a zero resets both to 0. This is the same swap idea as hi and lo.

60-Second Pitch

"This is Kadane's Algorithm, but a product needs two values. A negative number turns the smallest product into the largest. So I keep hi and lo, the largest and smallest product of a subarray that ends at the current number. For each x, the new hi is max(x, hi * x, lo * x) and the new lo is min(x, hi * x, lo * x). I compute both from the old values in one assignment. A zero resets both, and x alone starts the next run. I keep the largest hi in best. The time is O(N) and the space is O(1)."

Common Questions

Why does Kadane's Algorithm with one running value fail for products?

A negative number reverses the order of products. The smallest earlier product, which is a large negative number, becomes the largest product after you multiply by a negative x. One value forgets it. Keeping lo solves this.

What happens when the array contains a zero?

Both hi and lo become 0, because every product that includes the zero is 0. On the next number, the candidate x alone starts a new run. For [-2, 0, -1], the answer is 0.

What is the time and space complexity?

O(N) time, with three products and two comparisons per number. O(1) space, because only hi, lo and best exist.

Is there another method that does not use lo?

Yes. Scan from the left with a running product and again from the right, restarting at 1 after a zero. Return the largest product seen. It also takes O(N) time and O(1) space.

How does Maximum Length of Subarray With Positive Product (LC 1567) relate to this card?

It asks for a length, not a product. Keep the longest run with a positive product, pos, and the longest with a negative product, neg. A negative x swaps them, and a zero resets both to 0. It is the same two-ended idea as hi and lo.

SWE Reasoning

Spot it

  • The question asks for the best product of one unbroken run of an array.
  • The numbers can be negative or zero.
  • Kadane's rule max(x, curr * x) fails on a small example such as [-2, 3, -4].
  • A negative number can turn a very small product into a very large one.
  • A zero ends every run that crosses it.

The invariant, step by step

  1. Before the loop, hi, lo and best are all nums[0]. Only one subarray ends at index 0.
  2. For the next number x, hi is the largest and lo is the smallest product of a subarray that ends just before x.
  3. Every subarray that ends at x has the product x, hi * x or lo * x for the largest or smallest case. These three values are the only candidates.
  4. hi, lo = max(...), min(...) computes both new values from the old hi and lo in one assignment.
  5. best = max(best, hi) keeps the largest hi seen.
  6. After the last number, best covers every end index, so it is the answer.

Traps

  • Keeping only hi. Two negative numbers never combine. See the card's gotcha for [-2, 3, -4].
  • Two separate assignments. The second line reads the new hi. See the card's gotcha for [-2, -3, -4].
  • Dropping x from the candidates. After a zero, nothing can restart a run.
  • Starting best at 0. The subarray must hold at least one number. For [-3], the answer is -3, and a start at 0 returns 0.
  • Returning lo or the last hi. The answer is best, because the best run may end before the last number. For [2, 3, -2, 4], the last hi is 4 and the answer is 6.

Practice

Canonical LeetCode:Maximum Product Subarray (LC 152)Maximum Length of Subarray With Positive Product (LC 1567)
Theory Context•Dynamic Programming

Builds on Kadane's Algorithm, which you haven’t finished yet.

P1MediumBuilt on Linear DP~4 min speedrun

Kadane's Algorithm with a Product (Maximum Product Subarray)

Built on
Kadane's AlgorithmA negative number turns the smallest product into the largest, so keep both hi and lo, the largest and smallest product of a subarray that ends here.
The problem

Maximum Product Subarray (LC 152)(opens leetcode.com)

You get an integer array nums. A subarray is a run of numbers that sit next to each other. Multiply the numbers of a subarray to get its product.

Find the subarray with the largest product and return that product. The array can hold negative numbers and zeros. The subarray must hold at least one number.

Example 1
Input:nums = [2,3,-2,4]
Output:6
The subarray [2, 3] has product 6. No other subarray is larger: -2 makes any run that holds it smaller, and [4] is only 4.

Maximum Product Subarray

hi, lo = largest and smallest product ending at x ➔ a negative x swaps their roles ➔ keep the best hi
Spot it when: You need the best product of one unbroken run of an array, and the numbers may be negative or zero.
Maximum Product Subarray
Python
1def max_product(nums: list[int]) -> int:
2 """Maximum Product Subarray: the best product of one unbroken run, found in a single pass.
3 Time: O(N) | Space: O(1)
4 """
5 # hi, lo: the largest and smallest product of a subarray that ends at the current number; best: the largest hi seen so far
6 hi = lo = best = nums[0]
7 for x in nums[1:]:
8 # 1. Try x Alone, hi * x And lo * x:
9 # A negative x turns the smallest product into the largest, so both ends are extended. Both use the old hi and lo.
10 hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x)
11 
12 # 2. Track The Best:
13 # Every subarray ends at some index, so the largest hi seen at any index is the answer.
14 best = max(best, hi)
15 
16 return best
Invariant: Multiplying by a negative number flips the extremes: the biggest product becomes the smallest, and the smallest becomes the biggest. So after each x, keep both the largest and the smallest product: hi is the largest and lo is the smallest product of a subarray that ends at x, and best is the largest hi seen so far.

A negative x turns the smallest product that ends before it into the largest, so keep both ends: hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x). Every subarray that ends at x is x alone or an earlier subarray extended by x, so these three candidates cover all of them, and best keeps the largest hi seen. The trap is the order: compute hi and lo in one assignment from the old values, because if hi changes first, lo is computed from a different subarray.

See it run

Maximum Product Subarray, step by step

hi -2 · lo -2 · best -2

hi -2 · lo -2 · best -2

hi 0 · lo 0 · best 0

hi 0 · lo 0 · best 0

hi 0 · lo -1 · best 0

hi 0 · lo -1 · best 0

hi 3 · lo -3 · best 3

hi 3 · lo -3 · best 3

hi 12 · lo -12 · best 12

hi 12 · lo -12 · best 12

Each column is one index of nums. The rows hi and lo fill in as the steps run.

  • x the number being read
  • hi the largest product of a run that ends at x
  • lo the smallest product of a run that ends at x

Start: hi = lo = best = nums[0] = -2. Only one subarray ends at index 0.

Read x = 0. The candidates are x = 0, hi * x = -2 * 0 = 0, and lo * x = -2 * 0 = 0.

hi = max of the three = 0, and lo = min of the three = 0, so best = 0. The old run keeps growing.

Read x = -1. The candidates are x = -1, hi * x = 0 * -1 = 0, and lo * x = 0 * -1 = 0.

hi = max of the three = 0, and lo = min of the three = -1, so best = 0. The smallest old product times a negative x gave the new hi.

Read x = 3. The candidates are x = 3, hi * x = 0 * 3 = 0, and lo * x = -1 * 3 = -3.

hi = max of the three = 3, and lo = min of the three = -3, so best = 3. x alone is the largest, so a new run starts at x.

Read x = -4. The candidates are x = -4, hi * x = 3 * -4 = -12, and lo * x = -3 * -4 = 12.

hi = max of the three = 12, and lo = min of the three = -12, so best = 12. The smallest old product times a negative x gave the new hi.

Done: best = 12. The loop returns best, because the best run can end before the last number.

nums
0-2x
10
2-1
33
4-4
hi
-2hi
lo
-2lo
1 / 10
Gotchas1 of 3

Gotcha 1 of 3

  1. 1
    The trap

    Gotcha 1: Keeping only the largest product

    Mistake
    curr = max(x, curr * x)
    Fix
    hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x)

    What happens: A negative x turns the smallest product into the largest one. With only the largest product, the smallest product is lost, so a pair of negative numbers never combines into a positive product.

    Example: Maximum Product Subarray (LC 152): nums = [-2, 3, -4]
    Mistake: returns 3Fix: returns 24
  2. 2

    Gotcha 2: Updating hi before computing lo

    Mistake
    hi = max(x, hi * x, lo * x)
    lo = min(x, hi * x, lo * x)
    Fix
    hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x)

    What happens: The second line reads the new hi, which is the largest product ending at x, not the largest product ending before x. hi * x then multiplies x twice, so lo describes a run that does not exist.

    Example: Maximum Product Subarray (LC 152): nums = [-2, -3, -4]
    Mistake: returns 72Fix: returns 12
  3. 3

    Gotcha 3: Leaving x out of the candidates

    Mistake
    hi, lo = max(hi * x, lo * x), min(hi * x, lo * x)
    Fix
    hi, lo = max(x, hi * x, lo * x), min(x, hi * x, lo * x)

    What happens: After a zero, hi and lo are both 0, and hi * x and lo * x stay 0. Only x alone can start a new run. Without it, every product after a zero is 0.

    Example: Maximum Product Subarray (LC 152): nums = [0, 2]
    Mistake: returns 0Fix: returns 2
Not this one if…
  • The best run is a sum, and adding a number never swaps the smallest and the largest, so one running value curr is enough, as in Maximum Subarray (LC 53). See Kadane's Algorithm

Deep Dive

Why the smallest product must be kept

In Kadane's Algorithm, a larger earlier value always gives a larger new value. A product does not follow this rule. Multiplying by a negative x reverses the order: the smallest earlier product becomes the largest new product.

So the state has two values for the subarrays that end at the current number. hi is the largest product and lo is the smallest product. lo is often negative, and one more negative x turns it into the next hi.

Example: for nums = [-2, 3, -4], after 3 the pair is hi = 3 and lo = -6. Then x = -4 gives lo * x = 24. The answer is 24. Without lo, the answer would be 3.

Why three candidates cover every subarray

A subarray that ends at x is x alone, or an earlier subarray that ends just before x, followed by x.

For the second form, the product is p * x, where p is the product of the earlier subarray. If x > 0, the largest result comes from the largest p, which is hi. If x < 0, it comes from the smallest p, which is lo. If x = 0, every result is 0.

So max(x, hi * x, lo * x) is the largest product that ends at x, and min(x, hi * x, lo * x) is the smallest. The tuple assignment computes both from the old hi and lo.

A zero resets the state. After x = 0, both hi and lo are 0. The next number starts a new run through the candidate x alone.

Trace and the cost

Trace for nums = [2, 3, -2, 4], as x, hi, lo, best:

  • 2, 2, 2, 2 (the start).
  • 3, 6, 3, 6.
  • -2, -2, -12, 6.
  • 4, 4, -48, 6.

The answer is 6, from [2, 3]. Trace for nums = [-2, 0, -1, 3, -4]: best is 12, from the run [-1, 3, -4]. The zero ends the earlier run, and the next run starts at -1.

The time is O(N), with three products per number. The space is O(1).

Products grow fast. With 40 copies of 2, the result is 1,099,511,627,776. Python integers have no limit. In a language with 32-bit or 64-bit integers, check the size limit, which LeetCode states for each problem.

Two other ways to the same answer

A second method uses prefix products. Scan from the left with a running product, and again from the right. After a zero, restart the running product at 1. The answer is the largest product seen in either scan. The reason is that the best subarray either has an even number of negative numbers, or it drops a negative number at one end. One of the two scans reaches it. This gives the same results as max_product on random arrays with zeros and negative numbers.

The variant Maximum Length of Subarray With Positive Product (LC 1567) keeps lengths and not products. Keep pos, the longest run ending here with a positive product, and neg, the longest with a negative product. A negative x swaps pos and neg, and a zero resets both to 0. This is the same swap idea as hi and lo.

60-Second Pitch

"This is Kadane's Algorithm, but a product needs two values. A negative number turns the smallest product into the largest. So I keep hi and lo, the largest and smallest product of a subarray that ends at the current number. For each x, the new hi is max(x, hi * x, lo * x) and the new lo is min(x, hi * x, lo * x). I compute both from the old values in one assignment. A zero resets both, and x alone starts the next run. I keep the largest hi in best. The time is O(N) and the space is O(1)."

Common Questions

Why does Kadane's Algorithm with one running value fail for products?

A negative number reverses the order of products. The smallest earlier product, which is a large negative number, becomes the largest product after you multiply by a negative x. One value forgets it. Keeping lo solves this.

What happens when the array contains a zero?

Both hi and lo become 0, because every product that includes the zero is 0. On the next number, the candidate x alone starts a new run. For [-2, 0, -1], the answer is 0.

What is the time and space complexity?

O(N) time, with three products and two comparisons per number. O(1) space, because only hi, lo and best exist.

Is there another method that does not use lo?

Yes. Scan from the left with a running product and again from the right, restarting at 1 after a zero. Return the largest product seen. It also takes O(N) time and O(1) space.

How does Maximum Length of Subarray With Positive Product (LC 1567) relate to this card?

It asks for a length, not a product. Keep the longest run with a positive product, pos, and the longest with a negative product, neg. A negative x swaps them, and a zero resets both to 0. It is the same two-ended idea as hi and lo.

SWE Reasoning

Spot it

  • The question asks for the best product of one unbroken run of an array.
  • The numbers can be negative or zero.
  • Kadane's rule max(x, curr * x) fails on a small example such as [-2, 3, -4].
  • A negative number can turn a very small product into a very large one.
  • A zero ends every run that crosses it.

The invariant, step by step

  1. Before the loop, hi, lo and best are all nums[0]. Only one subarray ends at index 0.
  2. For the next number x, hi is the largest and lo is the smallest product of a subarray that ends just before x.
  3. Every subarray that ends at x has the product x, hi * x or lo * x for the largest or smallest case. These three values are the only candidates.
  4. hi, lo = max(...), min(...) computes both new values from the old hi and lo in one assignment.
  5. best = max(best, hi) keeps the largest hi seen.
  6. After the last number, best covers every end index, so it is the answer.

Traps

  • Keeping only hi. Two negative numbers never combine. See the card's gotcha for [-2, 3, -4].
  • Two separate assignments. The second line reads the new hi. See the card's gotcha for [-2, -3, -4].
  • Dropping x from the candidates. After a zero, nothing can restart a run.
  • Starting best at 0. The subarray must hold at least one number. For [-3], the answer is -3, and a start at 0 returns 0.
  • Returning lo or the last hi. The answer is best, because the best run may end before the last number. For [2, 3, -2, 4], the last hi is 4 and the answer is 6.

Practice

Canonical LeetCode:Maximum Product Subarray (LC 152)Maximum Length of Subarray With Positive Product (LC 1567)
© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•