2898. Maximum Linear Stock Score 🔒
Problem Description
You are given a 1-indexed integer array prices
, where prices[i]
represents the price of a stock on the i-th
day. Your task is to select a subset of elements from prices
that forms a linear selection and maximizes the sum of selected prices.
A selection is defined by an array indexes
(also 1-indexed) that contains k
indices forming a subsequence of [1, 2, ..., n]
. This selection is considered linear if it satisfies the following condition:
For every consecutive pair of indices in the selection (starting from the second index), the difference in prices must equal the difference in indices. Mathematically:
prices[indexes[j]] - prices[indexes[j-1]] = indexes[j] - indexes[j-1]
for all1 < j <= k
This means if you select days i
and j
(where j > i
), the price increase per day must be exactly 1. For example, if you select day 2 with price 5 and day 5 with price 8, then 8 - 5 = 3
must equal 5 - 2 = 3
.
The score of a selection is the sum of all selected prices: prices[indexes[1]] + prices[indexes[2]] + ... + prices[indexes[k]]
.
Your goal is to find the maximum score possible from any valid linear selection.
The key insight is that for any linear selection, all selected elements must satisfy prices[i] - i = constant
. This transforms the problem into finding all elements with the same value of prices[i] - i
and selecting the group with the maximum sum.
Intuition
Let's think about what the linear condition really means. When we have a linear selection with indices [i, j]
, the condition states:
prices[j] - prices[i] = j - i
This can be rearranged to:
prices[j] - j = prices[i] - i
This is the key observation! For any two elements to be part of the same linear selection, they must have the same value of prices[index] - index
.
Let's extend this to three indices [i, j, k]
. For this to be linear:
prices[j] - prices[i] = j - i
impliesprices[j] - j = prices[i] - i
prices[k] - prices[j] = k - j
impliesprices[k] - k = prices[j] - j
Therefore, prices[i] - i = prices[j] - j = prices[k] - k
This pattern holds for any number of elements in a linear selection. All elements in a valid linear selection must have the same value of prices[index] - index
.
Now the problem becomes much simpler: instead of trying different combinations to form linear selections, we can:
- Group all indices by their
prices[i] - i
value - For each group, all elements can form a valid linear selection together
- The score of each group is the sum of all
prices[i]
in that group - The answer is the maximum score among all groups
This transforms a complex subsequence selection problem into a simple grouping and summation problem, which can be efficiently solved using a hash table to track the sum of prices for each distinct prices[i] - i
value.
Solution Approach
Based on our intuition that all elements in a linear selection must satisfy prices[i] - i = constant
, we can implement the solution using a hash table to group and sum elements efficiently.
Implementation Steps:
-
Create a hash table (Counter): We use a
Counter
objectcnt
to store the sum of prices for each distinct value ofprices[i] - i
. -
Iterate through the array: For each index
i
and corresponding pricex
in the prices array:- Calculate the key:
x - i
(which representsprices[i] - i
) - Add the price
x
to the sum for this key:cnt[x - i] += x
Note that we use 0-based indexing in the implementation, but since we're computing differences, the relative differences remain the same as with 1-based indexing.
- Calculate the key:
-
Find the maximum sum: After processing all elements, each key in the hash table represents a different group where all elements can form a valid linear selection. The value for each key is the sum of all prices in that group. We return the maximum value among all groups:
max(cnt.values())
.
Example Walkthrough:
If prices = [3, 5, 7, 10]
(using 0-based indexing):
- Index 0:
3 - 0 = 3
, add 3 tocnt[3]
- Index 1:
5 - 1 = 4
, add 5 tocnt[4]
- Index 2:
7 - 2 = 5
, add 7 tocnt[5]
- Index 3:
10 - 3 = 7
, add 10 tocnt[7]
Each element has a different prices[i] - i
value, so each forms its own group. The maximum score would be 10 (the single element at index 3).
Time and Space Complexity:
- Time:
O(n)
where n is the length of the prices array - Space:
O(n)
for the hash table in the worst case when all elements have differentprices[i] - i
values
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 a concrete example with prices = [1, 5, 3, 7, 8]
(using 1-based indexing as per the problem).
Step 1: Calculate prices[i] - i
for each element
Index (i) | Price | prices[i] - i |
---|---|---|
1 | 1 | 1 - 1 = 0 |
2 | 5 | 5 - 2 = 3 |
3 | 3 | 3 - 3 = 0 |
4 | 7 | 7 - 4 = 3 |
5 | 8 | 8 - 5 = 3 |
Step 2: Group elements by their prices[i] - i
value
- Group with value
0
: indices [1, 3] with prices [1, 3] - Group with value
3
: indices [2, 4, 5] with prices [5, 7, 8]
Step 3: Verify linear selections are valid
Let's verify group 3
forms a valid linear selection:
- Indices: [2, 4, 5]
- Between indices 2 and 4:
prices[4] - prices[2] = 7 - 5 = 2
and4 - 2 = 2
✓ - Between indices 4 and 5:
prices[5] - prices[4] = 8 - 7 = 1
and5 - 4 = 1
✓
Step 4: Calculate scores for each group
- Group
0
: sum = 1 + 3 = 4 - Group
3
: sum = 5 + 7 + 8 = 20
Step 5: Return the maximum score
The maximum score is 20, achieved by selecting indices [2, 4, 5] with prices [5, 7, 8].
This selection forms a linear pattern where the price increases by exactly 1 for each day gap in the selection.
Solution Implementation
1from typing import List
2from collections import Counter
3
4class Solution:
5 def maxScore(self, prices: List[int]) -> int:
6 # Create a counter to group elements by (value - index)
7 # Elements with the same (value - index) can be selected together
8 group_sums = Counter()
9
10 # Iterate through prices with their indices
11 for index, price in enumerate(prices):
12 # Group key is (price - index)
13 # Add the price to the sum for this group
14 group_key = price - index
15 group_sums[group_key] += price
16
17 # Return the maximum sum among all groups
18 return max(group_sums.values())
19
1class Solution {
2 public long maxScore(int[] prices) {
3 // Map to store the sum of prices grouped by (price - index)
4 // Key: (price - index), Value: sum of all prices with the same (price - index)
5 Map<Integer, Long> groupSums = new HashMap<>();
6
7 // Iterate through all prices and group them by (price - index)
8 for (int index = 0; index < prices.length; index++) {
9 // Calculate the group key: price - index
10 int groupKey = prices[index] - index;
11
12 // Add the current price to the sum of its group
13 // If the key doesn't exist, initialize with the current price
14 // If it exists, add the current price to the existing sum
15 groupSums.merge(groupKey, (long) prices[index], Long::sum);
16 }
17
18 // Find the maximum sum among all groups
19 long maxSum = 0;
20 for (long currentSum : groupSums.values()) {
21 maxSum = Math.max(maxSum, currentSum);
22 }
23
24 return maxSum;
25 }
26}
27
1class Solution {
2public:
3 long long maxScore(vector<int>& prices) {
4 // Map to store the sum of prices for each group
5 // Key: (price - index), Value: sum of prices in this group
6 unordered_map<int, long long> groupSums;
7
8 // Group items by (price - index) and calculate sum for each group
9 // Items with the same (price - index) can be picked together
10 // because picking item j after item i requires: prices[j] - prices[i] >= j - i
11 // which can be rewritten as: prices[j] - j >= prices[i] - i
12 for (int i = 0; i < prices.size(); ++i) {
13 int groupKey = prices[i] - i;
14 groupSums[groupKey] += prices[i];
15 }
16
17 // Find the maximum sum among all groups
18 long long maxSum = 0;
19 for (const auto& [key, sum] : groupSums) {
20 maxSum = max(maxSum, sum);
21 }
22
23 return maxSum;
24 }
25};
26
1/**
2 * Calculates the maximum score from an array of prices
3 * The score is calculated by grouping elements where price[i] - i is the same
4 * and summing their values
5 * @param prices - Array of price values
6 * @returns Maximum sum among all groups
7 */
8function maxScore(prices: number[]): number {
9 // Map to store the sum of prices for each group
10 // Key: price[i] - i (the grouping criterion)
11 // Value: sum of all prices in this group
12 const groupSums: Map<number, number> = new Map();
13
14 // Iterate through all prices
15 for (let index = 0; index < prices.length; ++index) {
16 // Calculate the group key for current element
17 const groupKey = prices[index] - index;
18
19 // Add current price to its corresponding group sum
20 // If group doesn't exist, initialize with 0
21 const currentSum = groupSums.get(groupKey) || 0;
22 groupSums.set(groupKey, currentSum + prices[index]);
23 }
24
25 // Return the maximum sum among all groups
26 return Math.max(...groupSums.values());
27}
28
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the prices
array. This is because:
- The code iterates through the
prices
array once usingenumerate()
, which takesO(n)
time - For each element, it performs constant time operations: computing
x - i
and updating the counter withcnt[x - i] += x
, which are bothO(1)
operations - Finding the maximum value in the counter using
max(cnt.values())
takesO(k)
time wherek
is the number of unique keys, and in the worst casek ≤ n
The space complexity is O(n)
, where n
is the length of the prices
array. This is because:
- The
Counter
objectcnt
stores key-value pairs where keys arex - i
values - In the worst case, all elements in
prices
could produce uniquex - i
values, resulting inn
different keys in the counter - Therefore, the space required is proportional to the input size
n
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Confusion Between 0-based and 1-based Indexing
One of the most common pitfalls is mixing up the indexing systems. The problem statement explicitly mentions that the array is 1-indexed, but most programming languages (including Python) use 0-based indexing.
The Pitfall: Developers might incorrectly adjust the formula by adding 1 to the index:
# INCORRECT approach
for index, price in enumerate(prices):
group_key = price - (index + 1) # Wrong! Trying to convert to 1-based
group_sums[group_key] += price
Why This is Wrong: The key insight is that we're looking for elements where the difference between price and index is constant. Since we're dealing with differences, the relative relationships remain the same whether we use 0-based or 1-based indexing:
- In 1-based:
prices[i] - i = constant
- In 0-based:
prices[i] - i = constant
(the constant value differs by 1, but grouping remains the same)
The Solution: Use the indexing system natural to your programming language without adjustment:
# CORRECT approach
for index, price in enumerate(prices):
group_key = price - index # Direct subtraction works correctly
group_sums[group_key] += price
2. Empty Array Edge Case
Another pitfall is not handling the edge case where the input array is empty.
The Pitfall:
def maxScore(self, prices: List[int]) -> int:
group_sums = Counter()
for index, price in enumerate(prices):
group_sums[price - index] += price
return max(group_sums.values()) # Fails if prices is empty!
The Solution: Add a check for empty input:
def maxScore(self, prices: List[int]) -> int:
if not prices:
return 0
group_sums = Counter()
for index, price in enumerate(prices):
group_sums[price - index] += price
return max(group_sums.values())
3. Misunderstanding the Linear Selection Condition
Some developers might incorrectly interpret the condition and try to find arithmetic progressions in the prices array directly, rather than understanding that the constraint relates price differences to index differences.
The Pitfall:
Attempting to find consecutive elements where prices[i+1] - prices[i] = 1
, which is NOT what the problem asks for.
The Solution:
Remember that the condition is about the relationship between price differences and index differences for selected elements (which may not be consecutive in the original array). The correct interpretation leads to the insight that all selected elements must have the same value of prices[i] - i
.
Which of the following array represent a max heap?
Recommended Readings
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
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!