解题思路与代码实现
问题描述
小F在“双十一”期间购买了 N 件商品。每件商品有一个价格 p[i],小F可以获得的优惠取决于该商品之前的一件商品。如果某一件商品的价格 p[i] 大于等于前面的某个商品 p[j],则小F可以享受该商品 p[j] 的价格作为优惠,前提是 p[j] 是离 p[i] 最近的且满足条件的商品。
例如:
- 给定价格数组
p = [9, 4, 5, 2, 4]:p[3] = 2之前没有商品的价格小于等于p[3],因此没有优惠。p[2] = 5可以享受最近的商品p[1] = 4的价格作为优惠。
任务是计算小F能获得的总优惠。
测试样例
-
样例1:
- 输入:
N = 5,p = [9, 4, 5, 2, 4] - 输出:
6
- 输入:
-
样例2:
- 输入:
N = 4,p = [1, 2, 3, 5] - 输出:
6
- 输入:
-
样例3:
- 输入:
N = 4,p = [4, 3, 2, 1] - 输出:
0
- 输入:
解题思路
为了高效地找到每个商品 p[i] 最接近且价格小于等于它的前一个商品 p[j], 我们可以使用 单调栈(Monotonic Stack)。具体步骤如下:
- 初始化一个空栈,用于存储商品的索引。
- 遍历价格数组 p 从左到右:
- 对于每个商品 p[i],弹出栈顶,直到找到第一个 p[j] ≤ p[i] 或者栈为空。
- 如果栈不为空,那么 p[j] 就是满足条件且离 p[i] 最近的商品,将 p[j] 加入总优惠。
- 将当前索引 i 压入栈中。
- **最终,**总优惠就是满足条件的所有 p[j] 之和。
通过这种方式,我们可以在 O(N) 的时间复杂度内完成整个过程。
代码实现
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
public static int solution(int N, int[] p) {
// write code here
// 使用栈来存储索引
Deque<Integer> stack = new ArrayDeque<>();
long totalDiscount = 0;
for (int i = 0; i < N; i++) {
// 弹出栈顶直到找到 p[j] <= p[i] 或者栈为空
while (!stack.isEmpty() && p[stack.peek()] > p[i]) {
stack.pop();
}
if (!stack.isEmpty()) {
// 最近的满足条件的 p[j]
totalDiscount += p[stack.peek()];
}
// 将当前索引压入栈中
stack.push(i);
}
return (int) totalDiscount;
}
public static void main(String[] args) {
System.out.println(solution(5, new int[] { 9, 4, 5, 2, 4 }) == 6);
System.out.println(solution(4, new int[] { 1, 2, 3, 5 }) == 6);
System.out.println(solution(4, new int[] { 4, 3, 2, 1 }) == 0);
}
}
代码说明
-
数据结构选择:
- 使用 栈(Deque) 来存储商品的索引,以便快速找到每个商品之前最近且价格小于等于它的商品。
-
遍历过程:
- 对于每个商品 p[i],不断弹出栈顶的索引 j,直到找到一个 p[j] ≤ p[i] 或者栈为空。
- 如果栈不为空,说明存在一个满足条件的商品 p[j],将其价格 p[j] 加入 总优惠。
- 将当前索引 i 压入栈中,作为可能后续商品的 j。
-
复杂度分析:
- 时间复杂度: O(N),每个元素最多被压入和弹出栈一次。
- 空间复杂度: O(N),最坏情况下,栈中可能存储所有的索引。
测试样例验证
-
样例1:
- 输入:
N = 5,p = [9, 4, 5, 2, 4] - 过程:
i=0: 无前置商品,优惠0,栈:[0]i=1:p[0]=9 > 4,弹出,栈为空,优惠0,栈:[1]i=2:p[1]=4 ≤ 5,优惠4,栈:[2]i=3:p[2]=5 > 2,弹出;p[1]=4 > 2,弹出,栈为空,优惠0,栈:[3]i=4:p[3]=2 ≤ 4,优惠2,栈:[4]
- 总优惠:
4 + 2 = 6 - 输出:
6
- 输入:
-
样例2:
- 输入:
N = 4,p = [1, 2, 3, 5] - 过程:
i=0: 无前置商品,优惠0,栈:[0]i=1:p[0]=1 ≤ 2,优惠1,栈:[1]i=2:p[1]=2 ≤ 3,优惠2,栈:[2]i=3:p[2]=3 ≤ 5,优惠3,栈:[3]
- 总优惠:
1 + 2 + 3 = 6 - 输出:
6
- 输入:
-
样例3:
- 输入:
N = 4,p = [4, 3, 2, 1] - 过程:
i=0: 无前置商品,优惠0,栈:[0]i=1:p[0]=4 > 3,弹出,栈为空,优惠0,栈:[1]i=2:p[1]=3 > 2,弹出,栈为空,优惠0,栈:[2]i=3:p[2]=2 > 1,弹出,栈为空,优惠0,栈:[3]
- 总优惠:
0 - 输出:
0
- 输入:
结论
通过使用单调栈的方法,我们能够高效地找到每个商品前面最近且价格小于等于它的商品,从而计算出小F可以获得的总优惠。该算法的时间复杂度为 O(N),适用于大规模数据。