Final Prices With a Special Discount in a Shop
EasyPrompt
You are given an integer array prices where prices[i] is the price of the ith item in a shop.
There is a special discount for items in the shop. If you buy the ith item, then you will receive a discount equivalent to prices[j] where j is the minimum index such that j > i and prices[j] <= prices[i]. Otherwise, you will not receive any discount at all.
Return an integer array answer where answer[i] is the final price you will pay for the ith item of the shop, considering the special discount.
Example 1:
Input: prices = [8,4,6,2,3]
Output: [4,2,4,2,3]
Explanation:
For item 0 with price[0]=8 you will receive a discount equivalent to prices[1]=4, therefore, the final price you will pay is 8 - 4 = 4.
For item 1 with price[1]=4 you will receive a discount equivalent to prices[3]=2, therefore, the final price you will pay is 4 - 2 = 2.
For item 2 with price[2]=6 you will receive a discount equivalent to prices[3]=2, therefore, the final price you will pay is 6 - 2 = 4.
For items 3 and 4 you will not receive any discount at all.Example 2:
Input: prices = [1,2,3,4,5]
Output: [1,2,3,4,5]
Explanation: In this case, for all items, you will not receive any discount at all.Example 3:
Input: prices = [10,1,1,6]
Output: [9,0,1,6]
Constraints:
1 <= prices.length <= 5001 <= prices[i] <= 1000
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly translates the problem statement into code. We iterate through each item and then scan all subsequent items to find the first one that offers a discount.
Algorithm
- Create a new array
answerof the same size aspricesto store the final prices. - Iterate through the
pricesarray with an indexifrom0ton-1, wherenis the length of the array. - For each
i, initialize adiscountvariable to0. - Start a nested loop with an index
jfromi + 1ton-1. - Inside the inner loop, check if
prices[j]is less than or equal toprices[i]. - If the condition is met, it means we've found the first applicable discount. Set
discount = prices[j]andbreakthe inner loop. - After the inner loop, calculate the final price for item
iasprices[i] - discountand store it inanswer[i]. - After the outer loop completes, return the
answerarray.
Walkthrough
We can solve this problem by using two nested loops. The outer loop iterates through each item i from the beginning to the end of the prices array. For each item i, the inner loop iterates through the subsequent items j (where j > i).
Inside the inner loop, we look for the first item j whose price prices[j] is less than or equal to the price of the current item prices[i]. If we find such an item, we calculate the discounted price prices[i] - prices[j], store it in our result, and break the inner loop since we only care about the first such j.
If the inner loop completes without finding any item j that satisfies the condition, it means no discount is applicable for item i. In this case, the final price is simply prices[i].
class Solution { public int[] finalPrices(int[] prices) { int n = prices.length; int[] answer = new int[n]; for (int i = 0; i < n; i++) { int discount = 0; for (int j = i + 1; j < n; j++) { if (prices[j] <= prices[i]) { discount = prices[j]; break; // Found the first valid discount } } answer[i] = prices[i] - discount; } return answer; }}Complexity
Time
O(n^2), where n is the number of items. In the worst-case scenario (e.g., a strictly increasing array), the inner loop runs approximately n times for each of the n items.
Space
O(n) to store the `answer` array. If we modify the input array in-place, the auxiliary space complexity would be O(1).
Trade-offs
Pros
Simple to understand and implement.
Directly follows the logic from the problem description.
Low auxiliary space complexity if allowed to modify the input array.
Cons
Inefficient for large input arrays due to its quadratic time complexity.
This problem can be optimized by recognizing it as a variation of the 'Next Smaller Element' problem. A monotonic stack is an ideal data structure for this, allowing us to find the next smaller or equal element for each item in a single pass.
Algorithm
- Initialize an empty
stackto store indices. - Initialize an
answerarray of the same size asprices. - Iterate through the
pricesarray from right to left (fromi = n-1down to0). - For each
i, while the stack is not empty and the price at the index on top of the stack (prices[stack.peek()]) is strictly greater thanprices[i], pop from the stack. - After the loop, if the stack is empty, there is no discount. Set
answer[i] = prices[i]. - Otherwise, the discount is
prices[stack.peek()]. Setanswer[i] = prices[i] - prices[stack.peek()]. - Push the current index
ionto the stack. - After iterating through all items, return the
answerarray.
Walkthrough
We can achieve a linear time solution using a monotonic stack. The stack will store indices of prices, maintaining a monotonically non-decreasing order of prices from bottom to top.
We iterate through the prices array from right to left. For each price prices[i], we look at the top of the stack. The elements on the stack represent items to the right of i.
While the stack is not empty and the price at the index on top of the stack is greater than prices[i], we pop from the stack. These popped items cannot be the discount for prices[i] or any item to its left (since prices[i] is smaller and closer).
After the while loop, if the stack is empty, it means no item to the right of i has a price less than or equal to prices[i]. The discount is 0.
If the stack is not empty, the index at the top of the stack corresponds to the first item to the right of i with a price less than or equal to prices[i]. This is the discount we apply.
Finally, we push the current index i onto the stack to be considered for items to its left. Since we process the array from right to left, we can directly calculate the final price for each item.
import java.util.Stack; class Solution { public int[] finalPrices(int[] prices) { int n = prices.length; int[] answer = new int[n]; Stack<Integer> stack = new Stack<>(); // Stack of indices for (int i = n - 1; i >= 0; i--) { // Pop elements from stack that are greater than current price while (!stack.isEmpty() && prices[stack.peek()] > prices[i]) { stack.pop(); } // If stack is empty, no discount if (stack.isEmpty()) { answer[i] = prices[i]; } else { // Top of stack is the next smaller or equal element answer[i] = prices[i] - prices[stack.peek()]; } // Push current index onto the stack stack.push(i); } return answer; }}Complexity
Time
O(n), where n is the number of items. Each index is pushed onto and popped from the stack at most once, so the total operations are linear.
Space
O(n) in the worst case for the stack (e.g., for a strictly increasing array like `[1, 2, 3, 4, 5]`). This is auxiliary space, in addition to the O(n) space required for the output array.
Trade-offs
Pros
Highly efficient with a linear time complexity.
Solves the problem in a single pass over the array.
Cons
Requires extra space for the stack.
The logic might be less intuitive than the brute-force approach for beginners.
Solutions
Solution
class Solution { public int [] finalPrices ( int [] prices ) { int n = prices . length ; int [] ans = new int [ n ]; for ( int i = 0 ; i < n ; ++ i ) { ans [ i ] = prices [ i ]; for ( int j = i + 1 ; j < n ; ++ j ) { if ( prices [ j ] <= prices [ i ]) { ans [ i ] -= prices [ j ]; break ; } } } return ans ; } }/** * @param {number[]} prices * @return {number[]} */ var finalPrices = function ( prices ) { for ( let i = 0 ; i < prices . length ; i ++ ) { for ( let j = i + 1 ; j < prices . length ; j ++ ) { if ( prices [ i ] >= prices [ j ]) { prices [ i ] -= prices [ j ]; break ; } } } return prices ; };class Solution : def finalPrices ( self , prices : List [ int ]) -> List [ int ]: ans = [] for i , v in enumerate ( prices ): ans . append ( v ) for j in range ( i + 1 , len ( prices )): if prices [ j ] <= v : ans [ - 1 ] -= prices [ j ] break return ansclass Solution { public: vector < int > finalPrices ( vector < int >& prices ) { int n = prices . size (); vector < int > ans ( n ); for ( int i = 0 ; i < n ; ++ i ) { ans [ i ] = prices [ i ]; for ( int j = i + 1 ; j < n ; ++ j ) { if ( prices [ j ] <= prices [ i ]) { ans [ i ] -= prices [ j ]; break ; } } } return ans ; } };Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.