价格优惠计算问题
一、问题重现
问题描述
小F在“双十一”期间购买了NN件商品。每件商品有一个价格p[i]p[i],小F可以获得的优惠取决于该商品之前的一件商品。如果某一件商品的价格p[i]p[i]大于等于前面的某个商品p[j]p[j],则小F可以享受该商品p[j]p[j]的价格作为优惠,前提是p[j]p[j]是离p[i]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
二、解题思路
-
初始化:定义一个栈
st和一个队列rep,用于存储商品价格。 -
遍历商品价格数组:对于每个商品价格
p[i],执行以下操作:-
检查栈顶元素:如果栈
st不为空,检查栈顶元素是否大于当前商品价格p[i]。- 如果栈顶元素大于
p[i],则将栈顶元素移到队列rep中,并从栈中弹出。 - 如果栈顶元素小于等于
p[i],则将栈顶元素累加到结果ans中,并退出循环。
- 如果栈顶元素大于
-
恢复栈状态:将队列
rep中的元素重新压入栈st中。 -
压入当前商品价格:将当前商品价格
p[i]压入栈st中。
-
-
返回结果:返回累加的结果
ans。
关键点
- 栈和队列的使用:栈
st用于存储商品价格,队列rep用于临时存储需要重新压入栈的元素。 - 检查栈顶元素:在遍历过程中,检查栈顶元素是否大于当前商品价格
p[i],如果是,则将栈顶元素移到队列rep中。 - 恢复栈状态:在每次遍历结束后,将队列
rep中的元素重新压入栈st中,以恢复栈的状态。 - 累加优惠:如果栈顶元素小于等于当前商品价格
p[i],则将其累加到结果ans中。
三、代码实现
int solution(int N, std::vector<int>& p) {
int ans = 0;
stack<int> st;
queue<int> rep;
for(int i = 0; i < N; ++i) {
while(!st.empty()) {
if(st.top() > p[i]) {
rep.push(st.top());
st.pop();
}
else {
ans += st.top();
break;
}
}
while (!rep.empty()) {
st.push(rep.front());
rep.pop();
}
st.push(p[i]);
}
return ans;
}
四、算法复杂度分析
时间复杂度
-
外层循环:外层循环遍历商品价格数组
p,时间复杂度为O(N)。 -
内层循环:
- 第一个
while循环:在每次外层循环中,第一个while循环会遍历栈st,直到找到一个满足条件的栈顶元素或栈为空。在最坏情况下,每次外层循环都会遍历整个栈,但由于栈的大小不会超过N,因此这个循环的总时间复杂度为O(N)。 - 第二个
while循环:在每次外层循环中,第二个while循环会将队列rep中的元素重新压入栈st。在最坏情况下,每次外层循环都会遍历整个队列,但由于队列的大小不会超过N,因此这个循环的总时间复杂度为O(N)。
- 第一个
空间复杂度
- 栈
st:栈st的最大大小为N,因此空间复杂度为O(N)。 - 队列
rep:队列rep的最大大小为N,因此空间复杂度为O(N)。