2921. Maximum Profitable Triplets With Increasing Prices II ๐
Problem Description
You are given two arrays prices
and profits
, both of length n
, where each index i
represents an item in a store with prices[i]
as its price and profits[i]
as its profit.
Your task is to select exactly three items that satisfy a specific ordering condition:
- The three items must be at indices
i
,j
, andk
wherei < j < k
- The prices must be strictly increasing:
prices[i] < prices[j] < prices[k]
When you select three valid items, the total profit is calculated as profits[i] + profits[j] + profits[k]
.
The goal is to find the maximum possible profit from selecting three items that meet these conditions. If no valid selection of three items exists, return -1
.
For example, if you have items with prices [1, 5, 3, 6]
and profits [4, 3, 2, 5]
, you could select items at indices 0, 1, and 3 (with prices 1 < 5 < 6), giving you a total profit of 4 + 3 + 5 = 12.
The solution uses Binary Indexed Trees to efficiently track the maximum profit available to the left and right of each position. For each potential middle item j
, it finds the best item i
with a lower price on the left and the best item k
with a higher price on the right, then combines their profits to find the optimal selection.
Intuition
The key insight is to think of this problem as finding an optimal "middle" element. For any valid triplet (i, j, k)
, we can consider j
as the middle element and ask: what's the best choice for i
on the left and k
on the right?
If we fix the middle element at position j
, we need:
- The best item
i
wherei < j
andprices[i] < prices[j]
(to maximizeprofits[i]
) - The best item
k
wherek > j
andprices[k] > prices[j]
(to maximizeprofits[k]
)
This transforms the problem from finding all possible triplets (which would be O(nยณ)
) to iterating through each potential middle element and finding the best left and right partners (which can be done more efficiently).
The challenge is: how do we quickly find "the maximum profit among all items with price less than X" as we process the array? This is a classic range maximum query problem that can be solved with a Binary Indexed Tree (Fenwick Tree).
For the left side, we process items from left to right, and at each position, we query for the maximum profit among all previously seen items with smaller prices. We then update our data structure with the current item.
For the right side, we need items with larger prices. A clever trick is to process from right to left and use inverted prices (max_price + 1 - prices[i]
). This inversion transforms "finding items with larger prices" into "finding items with smaller inverted prices", allowing us to use the same BIT query logic.
By precomputing the best left partner for each position in left[i]
and the best right partner in right[i]
, we can then simply iterate through all positions as potential middle elements and calculate left[i] + profits[i] + right[i]
to find the maximum total profit.
Learn more about Segment Tree patterns.
Solution Approach
The solution uses two Binary Indexed Trees (BITs) to efficiently maintain and query maximum profits based on price constraints.
Binary Indexed Tree Implementation:
The BinaryIndexedTree
class provides two key operations:
update(x, v)
: Updates positionx
with valuev
, maintaining the maximum value at each positionquery(x)
: Returns the maximum value among all positions from 1 tox
Main Algorithm Steps:
-
Initialize data structures:
- Create arrays
left[i]
andright[i]
to store the maximum profit to the left and right of each position - Find the maximum price
m
to determine the BIT size - Create two BITs:
tree1
for left-side processing andtree2
for right-side processing
- Create arrays
-
Build left array (left-to-right pass):
for i, x in enumerate(prices): left[i] = tree1.query(x - 1) # Get max profit where price < x tree1.update(x, profits[i]) # Add current item to BIT
- For each position
i
, query the BIT for the maximum profit among all items with prices less thanprices[i]
- Update the BIT with the current item's profit at price position
- For each position
-
Build right array (right-to-left pass):
for i in range(n - 1, -1, -1): x = m + 1 - prices[i] # Invert the price right[i] = tree2.query(x - 1) # Get max profit where original price > prices[i] tree2.update(x, profits[i]) # Add current item to BIT
- Process items from right to left
- Use price inversion trick:
m + 1 - prices[i]
converts "finding larger prices" to "finding smaller inverted prices" - This allows us to use the same BIT query logic for both left and right sides
-
Calculate maximum profit:
return max((l + x + r for l, x, r in zip(left, profits, right) if l and r), default=-1)
- For each position as the middle element, calculate total profit:
left[i] + profits[i] + right[i]
- Only consider positions where both
left[i]
andright[i]
are non-zero (valid triplets exist) - Return the maximum profit found, or
-1
if no valid triplet exists
- For each position as the middle element, calculate total profit:
Time Complexity: O(n log m)
where n
is the array length and m
is the maximum price value
Space Complexity: O(n + m)
for the arrays and BIT structures
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with a small example:
prices = [2, 4, 1, 5, 3]
profits = [3, 6, 7, 2, 8]
Step 1: Initialize
- Maximum price
m = 5
- Create
left
andright
arrays of size 5, initialized to 0 - Create two Binary Indexed Trees with size 6 (to handle prices 1-5)
Step 2: Build left array (left-to-right pass)
Processing index 0 (price=2, profit=3):
- Query BIT1 for max profit where price < 2: returns 0 (no items yet)
left[0] = 0
- Update BIT1: position 2 gets value 3
Processing index 1 (price=4, profit=6):
- Query BIT1 for max profit where price < 4: returns 3 (from price=2)
left[1] = 3
- Update BIT1: position 4 gets value 6
Processing index 2 (price=1, profit=7):
- Query BIT1 for max profit where price < 1: returns 0 (no smaller prices)
left[2] = 0
- Update BIT1: position 1 gets value 7
Processing index 3 (price=5, profit=2):
- Query BIT1 for max profit where price < 5: returns 7 (best among prices 1,2,4)
left[3] = 7
- Update BIT1: position 5 gets value 2
Processing index 4 (price=3, profit=8):
- Query BIT1 for max profit where price < 3: returns 7 (from price=1)
left[4] = 7
- Update BIT1: position 3 gets value 8
Result: left = [0, 3, 0, 7, 7]
Step 3: Build right array (right-to-left pass)
Processing index 4 (price=3, profit=8):
- Inverted price = 6 - 3 = 3
- Query BIT2 for max profit where inverted price < 3: returns 0 (no items yet)
right[4] = 0
- Update BIT2: position 3 gets value 8
Processing index 3 (price=5, profit=2):
- Inverted price = 6 - 5 = 1
- Query BIT2 for max profit where inverted price < 1: returns 0 (no valid items)
right[3] = 0
- Update BIT2: position 1 gets value 2
Processing index 2 (price=1, profit=7):
- Inverted price = 6 - 1 = 5
- Query BIT2 for max profit where inverted price < 5: returns 8 (from original price=3)
right[2] = 8
- Update BIT2: position 5 gets value 7
Processing index 1 (price=4, profit=6):
- Inverted price = 6 - 4 = 2
- Query BIT2 for max profit where inverted price < 2: returns 2 (from original price=5)
right[1] = 2
- Update BIT2: position 2 gets value 6
Processing index 0 (price=2, profit=3):
- Inverted price = 6 - 2 = 4
- Query BIT2 for max profit where inverted price < 4: returns 8 (best among original prices 3,4,5)
right[0] = 8
- Update BIT2: position 4 gets value 3
Result: right = [8, 2, 8, 0, 0]
Step 4: Calculate maximum profit
For each position as middle element:
- Position 0: left[0]=0, invalid (no item with smaller price on left)
- Position 1: left[1]=3, profits[1]=6, right[1]=2 โ Total = 3+6+2 = 11
- Position 2: left[2]=0, invalid (no item with smaller price on left)
- Position 3: left[3]=7, profits[3]=2, right[3]=0, invalid (no item with larger price on right)
- Position 4: left[4]=7, profits[4]=8, right[4]=0, invalid (no item with larger price on right)
Maximum profit = 11 (selecting items at indices 0, 1, 3 with prices 2 < 4 < 5 and profits 3+6+2=11)
Actually, let me recalculate the right array more carefully. When processing right-to-left, we want items with prices greater than the current price. The inverted price trick helps us find these.
After careful recalculation, the valid triplet would be indices (2, 4, 3) with prices (1, 3, 5) giving profits 7+8+2=17, or indices (0, 1, 3) with prices (2, 4, 5) giving profits 3+6+2=11. The maximum would be 17.
Solution Implementation
1class BinaryIndexedTree:
2 """
3 A Binary Indexed Tree (Fenwick Tree) modified to support range maximum queries.
4 Used to efficiently find the maximum value in a range.
5 """
6
7 def __init__(self, n: int):
8 """
9 Initialize the Binary Indexed Tree.
10
11 Args:
12 n: The size of the tree (maximum index value)
13 """
14 self.size = n
15 self.tree = [0] * (n + 1) # 1-indexed array for BIT operations
16
17 def update(self, index: int, value: int):
18 """
19 Update the tree with a new value at the given index.
20 Maintains the maximum value at each node.
21
22 Args:
23 index: The position to update (1-indexed)
24 value: The value to update with (keeps maximum)
25 """
26 while index <= self.size:
27 self.tree[index] = max(self.tree[index], value)
28 # Move to next index affected by this update
29 # Adding the lowest set bit moves to parent in BIT
30 index += index & -index
31
32 def query(self, index: int) -> int:
33 """
34 Query the maximum value from index 1 to the given index.
35
36 Args:
37 index: The upper bound of the range query (1-indexed)
38
39 Returns:
40 The maximum value in range [1, index]
41 """
42 max_value = 0
43 while index > 0:
44 max_value = max(max_value, self.tree[index])
45 # Move to previous range by removing the lowest set bit
46 index -= index & -index
47 return max_value
48
49
50class Solution:
51 def maxProfit(self, prices: List[int], profits: List[int]) -> int:
52 """
53 Find the maximum profit from selecting three items i < j < k
54 where prices[i] < prices[j] < prices[k].
55
56 Args:
57 prices: List of item prices
58 profits: List of corresponding profits for each item
59
60 Returns:
61 Maximum sum of profits[i] + profits[j] + profits[k] where the
62 price constraint is satisfied, or -1 if no valid triplet exists
63 """
64 n = len(prices)
65
66 # Arrays to store maximum profit from valid items to the left and right
67 max_profit_left = [0] * n # Max profit from items with smaller price to the left
68 max_profit_right = [0] * n # Max profit from items with larger price to the right
69
70 # Find the maximum price to determine BIT size
71 max_price = max(prices)
72
73 # Two BITs: one for left-to-right scan, one for right-to-left scan
74 left_tree = BinaryIndexedTree(max_price + 1)
75 right_tree = BinaryIndexedTree(max_price + 1)
76
77 # First pass: Find maximum profit from items with smaller prices to the left
78 for i, current_price in enumerate(prices):
79 # Query for maximum profit among all items with price < current_price
80 max_profit_left[i] = left_tree.query(current_price - 1)
81 # Update tree with current item's profit at its price position
82 left_tree.update(current_price, profits[i])
83
84 # Second pass: Find maximum profit from items with larger prices to the right
85 for i in range(n - 1, -1, -1):
86 # Transform price to handle reverse ordering (larger prices query)
87 # We want items with price > current_price, so we reverse the scale
88 reversed_price = max_price + 1 - prices[i]
89 # Query for maximum profit among all items with price > current_price
90 max_profit_right[i] = right_tree.query(reversed_price - 1)
91 # Update tree with current item's profit at its reversed price position
92 right_tree.update(reversed_price, profits[i])
93
94 # Find the maximum sum where both left and right have valid items (non-zero profit)
95 # For each middle item j, calculate: profit_left[j] + profit[j] + profit_right[j]
96 return max(
97 (left_profit + middle_profit + right_profit
98 for left_profit, middle_profit, right_profit in zip(max_profit_left, profits, max_profit_right)
99 if left_profit and right_profit), # Ensure valid triplet exists
100 default=-1 # Return -1 if no valid triplet found
101 )
102
1/**
2 * Binary Indexed Tree (Fenwick Tree) for range maximum queries
3 * This implementation supports finding the maximum value in a prefix range
4 */
5class BinaryIndexedTree {
6 private int size; // Size of the tree
7 private int[] tree; // Tree array storing maximum values
8
9 /**
10 * Constructor to initialize the Binary Indexed Tree
11 * @param size The size of the tree
12 */
13 public BinaryIndexedTree(int size) {
14 this.size = size;
15 this.tree = new int[size + 1]; // 1-indexed array
16 }
17
18 /**
19 * Updates the tree by propagating the maximum value upwards
20 * @param index The position to update (1-indexed)
21 * @param value The value to potentially update with
22 */
23 public void update(int index, int value) {
24 // Traverse upwards in the tree using the last set bit
25 while (index <= size) {
26 tree[index] = Math.max(tree[index], value);
27 index += index & -index; // Add the last set bit to move to parent
28 }
29 }
30
31 /**
32 * Queries the maximum value in the range [1, index]
33 * @param index The end position of the query range (1-indexed)
34 * @return The maximum value in the range
35 */
36 public int query(int index) {
37 int maxValue = 0;
38 // Traverse downwards in the tree
39 while (index > 0) {
40 maxValue = Math.max(maxValue, tree[index]);
41 index -= index & -index; // Remove the last set bit to move to previous range
42 }
43 return maxValue;
44 }
45}
46
47/**
48 * Solution class for finding maximum profit from selecting exactly 3 items
49 * where prices[i] < prices[j] < prices[k] for indices i < j < k
50 */
51class Solution {
52 /**
53 * Finds the maximum profit by selecting 3 items with strictly increasing prices
54 * @param prices Array of item prices
55 * @param profits Array of item profits
56 * @return Maximum total profit, or -1 if no valid triplet exists
57 */
58 public int maxProfit(int[] prices, int[] profits) {
59 int itemCount = prices.length;
60 int[] maxProfitLeft = new int[itemCount]; // Max profit from left with smaller price
61 int[] maxProfitRight = new int[itemCount]; // Max profit from right with larger price
62
63 // Find the maximum price to determine tree size
64 int maxPrice = 0;
65 for (int price : prices) {
66 maxPrice = Math.max(maxPrice, price);
67 }
68
69 // Tree for finding max profit among items with smaller prices on the left
70 BinaryIndexedTree leftTree = new BinaryIndexedTree(maxPrice + 1);
71
72 // Tree for finding max profit among items with larger prices on the right
73 BinaryIndexedTree rightTree = new BinaryIndexedTree(maxPrice + 1);
74
75 // Build left array: for each position, find max profit from items on left with smaller price
76 for (int i = 0; i < itemCount; i++) {
77 int currentPrice = prices[i];
78 // Query for max profit among all items with price < currentPrice
79 maxProfitLeft[i] = leftTree.query(currentPrice - 1);
80 // Update tree with current item's profit at its price position
81 leftTree.update(currentPrice, profits[i]);
82 }
83
84 // Build right array: for each position, find max profit from items on right with larger price
85 for (int i = itemCount - 1; i >= 0; i--) {
86 // Transform price to handle "greater than" queries using BIT
87 // We want items with price > prices[i], so we use inverted index
88 int invertedPrice = maxPrice + 1 - prices[i];
89 // Query for max profit among all items with price > currentPrice
90 maxProfitRight[i] = rightTree.query(invertedPrice - 1);
91 // Update tree with current item's profit at its inverted price position
92 rightTree.update(invertedPrice, profits[i]);
93 }
94
95 // Find the maximum total profit by considering each item as the middle element
96 int maxTotalProfit = -1;
97 for (int i = 0; i < itemCount; i++) {
98 // Check if current item can be the middle of a valid triplet
99 if (maxProfitLeft[i] > 0 && maxProfitRight[i] > 0) {
100 int totalProfit = maxProfitLeft[i] + profits[i] + maxProfitRight[i];
101 maxTotalProfit = Math.max(maxTotalProfit, totalProfit);
102 }
103 }
104
105 return maxTotalProfit;
106 }
107}
108
1class BinaryIndexedTree {
2private:
3 int size; // Size of the tree (1-indexed)
4 vector<int> tree; // Binary indexed tree array
5
6public:
7 // Constructor: Initialize BIT with given size
8 BinaryIndexedTree(int n) {
9 this->size = n;
10 tree.resize(n + 1, 0); // 1-indexed array, initialized to 0
11 }
12
13 // Update the tree with maximum value at position x
14 void update(int x, int value) {
15 // Propagate the update to all affected nodes
16 while (x <= size) {
17 tree[x] = max(tree[x], value); // Store maximum value
18 x += x & -x; // Move to next node using lowbit
19 }
20 }
21
22 // Query the maximum value in range [1, x]
23 int query(int x) {
24 int maxValue = 0;
25 // Traverse the tree to find maximum
26 while (x > 0) {
27 maxValue = max(maxValue, tree[x]);
28 x -= x & -x; // Move to parent node using lowbit
29 }
30 return maxValue;
31 }
32};
33
34class Solution {
35public:
36 int maxProfit(vector<int>& prices, vector<int>& profits) {
37 int n = prices.size();
38 vector<int> leftMaxProfit(n, 0); // Max profit from left side for each position
39 vector<int> rightMaxProfit(n, 0); // Max profit from right side for each position
40
41 // Find the maximum price to determine BIT size
42 int maxPrice = *max_element(prices.begin(), prices.end());
43
44 // Create two BITs for left and right processing
45 BinaryIndexedTree leftTree(maxPrice + 1);
46 BinaryIndexedTree rightTree(maxPrice + 1);
47
48 // Process from left to right: find max profit with smaller price on the left
49 for (int i = 0; i < n; ++i) {
50 int currentPrice = prices[i];
51 // Query maximum profit from all prices less than current price
52 leftMaxProfit[i] = leftTree.query(currentPrice - 1);
53 // Update tree with current profit at current price
54 leftTree.update(currentPrice, profits[i]);
55 }
56
57 // Process from right to left: find max profit with larger price on the right
58 for (int i = n - 1; i >= 0; --i) {
59 // Transform price to handle "greater than" queries using BIT
60 int transformedPrice = maxPrice + 1 - prices[i];
61 // Query maximum profit from all prices greater than current price
62 rightMaxProfit[i] = rightTree.query(transformedPrice - 1);
63 // Update tree with current profit at transformed price
64 rightTree.update(transformedPrice, profits[i]);
65 }
66
67 // Find the maximum sum of three profits where middle element satisfies conditions
68 int maxTotalProfit = -1;
69 for (int i = 0; i < n; ++i) {
70 // Check if there exists valid left and right elements
71 if (leftMaxProfit[i] > 0 && rightMaxProfit[i] > 0) {
72 // Calculate total profit: left + middle + right
73 int totalProfit = leftMaxProfit[i] + profits[i] + rightMaxProfit[i];
74 maxTotalProfit = max(maxTotalProfit, totalProfit);
75 }
76 }
77
78 return maxTotalProfit;
79 }
80};
81
1// Binary Indexed Tree (Fenwick Tree) for range maximum queries
2// Array to store the tree nodes
3let n: number;
4let c: number[];
5
6// Initialize the Binary Indexed Tree with size n
7function initBIT(size: number): void {
8 n = size;
9 c = Array(n + 1).fill(0);
10}
11
12// Update the tree at position x with maximum value v
13// Uses the BIT update pattern: x += x & -x to traverse parent nodes
14function update(x: number, v: number): void {
15 while (x <= n) {
16 c[x] = Math.max(c[x], v);
17 x += x & -x; // Move to next position using lowbit
18 }
19}
20
21// Query the maximum value in range [1, x]
22// Uses the BIT query pattern: x -= x & -x to traverse the tree
23function query(x: number): number {
24 let maxValue = 0;
25 while (x > 0) {
26 maxValue = Math.max(maxValue, c[x]);
27 x -= x & -x; // Move to parent using lowbit
28 }
29 return maxValue;
30}
31
32// Find maximum profit from selecting exactly 3 items with strictly increasing prices
33function maxProfit(prices: number[], profits: number[]): number {
34 const length: number = prices.length;
35
36 // Arrays to store maximum profit to the left and right of each index
37 const leftMaxProfit: number[] = Array(length).fill(0);
38 const rightMaxProfit: number[] = Array(length).fill(0);
39
40 // Find the maximum price to determine BIT size
41 const maxPrice = Math.max(...prices);
42
43 // First pass: Calculate maximum profit for items with smaller price to the left
44 initBIT(maxPrice + 1);
45 for (let i = 0; i < length; i++) {
46 const currentPrice: number = prices[i];
47 // Query maximum profit from items with price < currentPrice
48 leftMaxProfit[i] = query(currentPrice - 1);
49 // Update tree with current item's profit
50 update(currentPrice, profits[i]);
51 }
52
53 // Second pass: Calculate maximum profit for items with larger price to the right
54 initBIT(maxPrice + 1);
55 for (let i = length - 1; i >= 0; i--) {
56 // Transform price to handle reverse order (larger prices)
57 const transformedPrice: number = maxPrice + 1 - prices[i];
58 // Query maximum profit from items with price > currentPrice
59 rightMaxProfit[i] = query(transformedPrice - 1);
60 // Update tree with current item's profit
61 update(transformedPrice, profits[i]);
62 }
63
64 // Find the maximum total profit by considering each item as the middle element
65 let maxTotalProfit: number = -1;
66 for (let i = 0; i < length; i++) {
67 // Check if current item can be middle (has valid left and right items)
68 if (leftMaxProfit[i] > 0 && rightMaxProfit[i] > 0) {
69 const totalProfit = leftMaxProfit[i] + profits[i] + rightMaxProfit[i];
70 maxTotalProfit = Math.max(maxTotalProfit, totalProfit);
71 }
72 }
73
74 return maxTotalProfit;
75}
76
Time and Space Complexity
Time Complexity: O(n ร log M)
The algorithm uses two Binary Indexed Trees (Fenwick Trees) to track maximum profits. For each of the n
elements in the prices array:
- In the first loop: For each price, we perform a
query
operation (which takesO(log M)
time) and anupdate
operation (which also takesO(log M)
time) - In the second loop: Similarly, for each price, we perform a
query
and anupdate
operation, each takingO(log M)
time
The Binary Indexed Tree operations (query
and update
) have time complexity of O(log M)
because:
- In
update
: we traverse up the tree by addingx & -x
(the lowest set bit), which takes at mostlog M
steps - In
query
: we traverse down by subtractingx & -x
, which also takes at mostlog M
steps
Since we process n
elements and perform O(log M)
operations for each element, the total time complexity is O(n ร log M)
.
Space Complexity: O(M)
The space is dominated by:
- Two Binary Indexed Trees, each using an array of size
M + 1
:O(M)
- Two auxiliary arrays
left
andright
of sizen
:O(n)
Since M
represents the maximum value in the prices array (which is at most 5000 in this problem) and typically M
could be larger than n
, the overall space complexity is O(M)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Handling of Duplicate Prices
One of the most common pitfalls is not properly handling duplicate prices. The problem requires strictly increasing prices (prices[i] < prices[j] < prices[k]
), but the Binary Indexed Tree implementation might accidentally include items with equal prices.
The Issue:
When querying tree.query(x - 1)
, we get the maximum profit from all items with prices from 1 to x-1
. This correctly excludes items with price x
, ensuring strict inequality. However, if multiple items have the same price, the BIT update order matters.
Example Problem Scenario:
prices = [3, 3, 5] profits = [1, 2, 3]
If we're not careful, when processing the second item (price=3), we might include the first item (also price=3) in our left array, violating the strict inequality requirement.
The Solution in the Code: The implementation correctly handles this by:
- Using
query(current_price - 1)
which excludes items with price equal tocurrent_price
- Processing items sequentially, so when we query for item
j
, we only see itemsi < j
in the tree
2. Off-by-One Errors in BIT Indexing
Binary Indexed Trees typically use 1-based indexing, but prices might be 0 or negative in the general case.
The Issue: If prices contain 0 or if we don't handle the indexing correctly, we might get runtime errors or incorrect results.
Example Problem:
prices = [0, 1, 2] # Price of 0 would cause issues profits = [5, 3, 4]
The Solution: The current implementation assumes all prices are positive integers. To handle zero or negative prices, you would need to:
# Add offset to ensure all prices are positive
min_price = min(prices)
offset = 1 - min_price if min_price <= 0 else 0
adjusted_prices = [p + offset for p in prices]
3. Memory Limit with Large Price Values
The BIT size is determined by the maximum price value, not the number of items.
The Issue:
If prices can be very large (e.g., prices = [1, 2, 1000000000]
), the BIT would need to allocate arrays of size 1000000001, causing memory issues.
The Solution: Use coordinate compression to map prices to a smaller range:
# Coordinate compression
unique_prices = sorted(set(prices))
price_map = {price: i + 1 for i, price in enumerate(unique_prices)}
compressed_prices = [price_map[p] for p in prices]
max_compressed = len(unique_prices)
4. Confusion with the Right Array Price Inversion
The trickiest part of the solution is understanding why we use m + 1 - prices[i]
for the right array.
The Issue: Developers might try to directly query for prices greater than the current price, which doesn't work with the standard BIT maximum query that finds max in range [1, x].
Why the Inversion Works:
- We want to find items with
price > current_price
to the right - BIT naturally finds maximum in range [1, x] (items with price โค x)
- By inverting prices: large prices become small inverted values
- Now querying for inverted values less than
m + 1 - current_price
gives us original prices greater thancurrent_price
Example:
# Original prices: [1, 3, 2, 4] # Max price m = 4 # Inverted prices: [4, 2, 3, 1] # For price=2, inverted=3, query(2) finds items with inverted price โค 2 # This corresponds to original prices โฅ 3
5. Edge Case: Arrays with Less Than 3 Elements
The implementation handles this correctly by returning -1 when no valid triplet exists, but it's worth noting.
The Issue: With fewer than 3 elements, no valid triplet can exist.
The Solution (already handled):
The max(..., default=-1)
ensures -1 is returned when no valid triplet is found, which naturally handles the case when n < 3
.
Which of these properties could exist for a graph but not a tree?
Recommended Readings
Segment Tree Faster Range Queries For this article we want to introduce the idea of a Segment Tree Segment Trees allow us to quickly perform range queries as well as range updates Suppose we have an array and we want to know the sum of a particular range of numbers as well
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donโt Miss This!