Loading problems...
TL;DR: The optimal solution uses a variable-size sliding window to maintain a running product, adding the current window size to the total count at every step to account for all valid subarrays ending at the current position.
The Subarray Product Less Than K problem asks us to calculate the total number of contiguous subarrays within an integer array nums such that the product of elements in that subarray is strictly less than a given integer k. This is a classic counting problem that requires an efficient traversal method to avoid redundant calculations found in naive approaches.
The most straightforward way to solve LeetCode 713 is to iterate through every possible contiguous subarray, calculate its product, and check if it meets the condition.
Naive Algorithm:
i to define the start of the subarray.j (starting from i) to define the end of the subarray.(i, j), calculate the product of elements nums[i...j].k, increment the counter.Pseudo-code:
textcount = 0 for i from 0 to n-1: product = 1 for j from i to n-1: product = product * nums[j] if product < k: count = count + 1 else: break // Optimization: Product will only grow, so stop early return count
Complexity Analysis:
Why it fails:
While correct, the time complexity is inefficient for the given constraints. With nums.length up to , results in approximately operations, which typically exceeds the time limit (usually around operations per second) for interview problems. We need a linear time solution.
The core insight relies on the relationship between a valid window and the number of valid subarrays it contains.
If a window defined by [left, right] has a product strictly less than k, then every contiguous subarray ending at right and starting at or after left also has a product less than k.
For example, if nums = [10, 5, 2] and the window is [10, 5, 2] (indices 0 to 2) with product 100:
[10, 5, 2] ends at index 2.[5, 2] ends at index 2.[2] ends at index 2.All of these are valid if the full window is valid. The number of such subarrays is exactly right - left + 1.
This observation allows us to count all valid subarrays ending at index right in time once the valid window [left, right] is established. We do not need to iterate backwards from right.
Visual Description:
Imagine a window expanding to the right by incrementing the right pointer. As we include a new number, the current_product increases. If current_product meets or exceeds k, the window is "too heavy." We must shrink the window from the left by dividing current_product by nums[left] and incrementing left. We repeat this shrinking process until the product is strictly less than k again. Once the condition is restored, the size of the current window (right - left + 1) represents the number of new valid subarrays introduced by the element at right.

Let's trace nums = [10, 5, 2, 6], k = 100.
left = 0, curr = 1, ans = 0.right = 0 (Value 10):
curr becomes .0 - 0 + 1 = 1 to ans. Valid subarray: [10].ans is 1.right = 1 (Value 5):
curr becomes .1 - 0 + 1 = 2 to ans. Valid subarrays: [5], .right = 2 (Value 2):
curr becomes .nums[0] (10). = 10. Increment to 1.right = 3 (Value 6):
curr becomes .3 - 1 + 1 = 3 to ans. Valid subarrays: [6], , .The algorithm correctness relies on the invariant that at the end of every iteration of the right loop, the window [left, right] represents the longest contiguous subarray ending at right with a product strictly less than k.
Because the window [left, right] is valid, any subarray starting between left and right and ending at right is also valid (due to the positive integer constraint). The number of such subarrays is right - left + 1. By summing this value at each step, we count every valid subarray exactly once—specifically, at the iteration where that subarray ends. This ensures no duplicates and no omissions.
cppclass Solution { public: int numSubarrayProductLessThanK(vector<int>& nums, int k) { // Edge case: Since all nums[i] >= 1, product is always >= 1. // If k <= 1, no product can be strictly less than k. if (k <= 1) return 0; int left = 0; long long current_product = 1; // Use long long to prevent overflow int count = 0; for (int right = 0; right < nums.size(); ++right) { current_product *= nums[right]; // Shrink window while product is too large while (current_product >= k) { current_product /= nums[left]; left++; } // Add the number of valid subarrays ending at 'right' count += (right - left + 1); } return count; } };
javaclass Solution { public int numSubarrayProductLessThanK(int[] nums, int k) { // Edge case: Since elements are >= 1, product is >= 1. // If k <= 1, strictly less than k is impossible. if (k <= 1) return 0; int left = 0; long currentProduct = 1; int count = 0; for (int right = 0; right < nums.length; right++) { currentProduct *= nums[right]; // Shrink the window from the left if constraint is violated while (currentProduct >= k) { currentProduct /= nums[left]; left++; } // All subarrays ending at 'right' within the window are valid count += (right - left + 1); } return count; } }
pythonclass Solution: def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int: # Edge case: If k <= 1, no subarray product (>=1) can be < k if k <= 1: return 0 left = 0 current_product = 1 count = 0 for right in range(len(nums)): current_product *= nums[right] # Shrink window while product is invalid while current_product >= k: current_product //= nums[left] left += 1 # Add count of valid subarrays ending at current right count += (right - left + 1) return count
right pointer iterates through the array exactly once.left pointer also moves monotonically from 0 to and never moves backward.left, right, current_product, count) for storage, regardless of the input size.The Sliding Window - Variable Size (Condition-Based) pattern is a fundamental technique for array and string problems. It applies similarly to:
Mastering LeetCode 713 provides the template for solving any problem involving contiguous subarrays satisfying a monotonic constraint.
Q: Why does my solution fail with Time Limit Exceeded (TLE)? Mistake: Using the brute force nested loop approach (). Why: The constraints allow up to 30,000. operations is too slow for the 1-second time limit. You must use the sliding window approach.
[10, 5]ans is 3.currleft2 - 1 + 1 = 2 to ans. Valid subarrays: [2], [5, 2].ans is 5.[2, 6][5, 2, 6]ans is 8.Q: Why does my code return a non-zero answer when k = 0 or k = 1?
Mistake: Failing to handle k <= 1.
Why: The problem states elements are positive integers. Thus, the minimum product is 1. If k is 0 or 1, no product can be strictly less than k. Without an explicit check, the logic right - left + 1 might erroneously add counts if the while loop logic isn't perfectly robust against empty windows.
Consequence: Incorrect output for edge cases.
Q: Why is my answer slightly off (e.g., missing some subarrays)?
Mistake: Incorrectly calculating the number of subarrays.
Why: A common error is adding 1 (just the current element) instead of right - left + 1.
Consequence: This counts only single-element subarrays or fails to account for valid longer subarrays ending at the current index.
Q: Why do I get division by zero errors?
Mistake: Assuming the window is non-empty before dividing.
Why: In rare logic structures (specifically if not handling k <= 1), the while loop might run until left > right. If you try to access nums[left] when left is out of bounds or divide when the product is effectively reset, it causes errors.
Consequence: Runtime errors. The standard pattern logic prevents this if k <= 1 is handled first.