题目链接
https://leetcode.cn/problems/online-stock-span/
题目
我的思路
方案一 LinkedList,从后往前遍历,超时
用LinkedList存储每一次添加进来的price,然后从后往前遍历,找出连续小于等当前位置数的个数,不过,超时
import java.util.LinkedList;
import java.util.List;
class StockSpanner {
private List<Integer> list;
public StockSpanner() {
list = new LinkedList<>();
}
public int next(int price) {
list.add(price);
int cnt = 0;
int i = list.size() - 1;
while (price >= list.get(i)){
cnt++;
i--;
}
return cnt;
}
}
/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner obj = new StockSpanner();
* int param_1 = obj.next(price);
*/
方案二 两个Stack,超时
import java.util.Stack;
public class StockSpanner {
private Stack<Integer> s1, s2;
public StockSpanner() {
s1 = new Stack<>();
s2 = new Stack<>();
}
public int next(int price) {
int cnt = 1;
while (!s1.isEmpty() && price >= s1.peek()) {
s2.add(s1.pop());
cnt++;
}
while (!s2.isEmpty()) {
s1.add(s2.pop());
}
s1.add(price);
return cnt;
}
}
/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner obj = new StockSpanner();
* int param_1 = obj.next(price);
*/
官方思路 单调栈 计算差值
调用next时,输入的是新的一天的股票价格,需要返回包含在此日内的,往前数最多有连续多少日的股票价格是小于等于今日的股票价格的。
如果把每日的price当成数组不同下标的值,即需要求出每个值与上一个更大元素之间的下标之差。
这种题目可以用单调栈来求解。
此题在具体解法上,栈的元素可以是股票价格的下标(即天数)和股票价格的二元数对,并且在栈中插入一个最大值作为天数为-1天的价格,来保证栈不会为空。
调用next时,先将栈中价格小于等于此时price的元素都弹出,直到遇到一个大于price的值,并将price入栈,计算下标返回差
import java.util.Stack;
public class StockSpanner {
private Stack<int[]> s1;
private int idx;
public StockSpanner() {
s1 = new Stack<>();
s1.add(new int[]{-1, Integer.MAX_VALUE});
idx = -1;
}
public int next(int price) {
while (price >= s1.peek()[1]) {
s1.pop();
}
idx++;
int res = idx - s1.peek()[0];
s1.add(new int[]{idx, price});
return res;
}
}
/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner obj = new StockSpanner();
* int param_1 = obj.next(price);
*/
其他解法
方案一 利用堆栈实现
https://leetcode.cn/problems/online-stock-span/solution/-by-muse-77-byhj/
首先,根据题目描述,可以发现只有股票趋势是下降的情况下,才会统计跨度日期。
这里的股票趋势下降,应该是从后往前看,是下降趋势时,才进行统计。
可以利用堆栈来进行跨度日期的计算。堆栈操作有如下三种情况:
- 如果堆栈为空,则直接入栈
- 如果栈顶元素price 大于 输入股票的price,则直接入栈
- 如果栈顶元素的price 小于 输入股票的price,则将栈顶元素出栈,并将栈顶元素的day值加到“输入股票”的day值上。然后再对比下一个栈顶元素,操作以此类推,直到发现当前的栈顶元素大于输入股票的price,则将输入股票入栈即可
import java.util.Stack;
public class StockSpanner {
private Stack<Stock> stack;
public StockSpanner() {
stack = new Stack<>();
}
public int next(int price) {
int day = 1;
while (!stack.isEmpty() && stack.peek().price <= price) {
day += stack.pop().day;
}
stack.add(new Stock(price, day));
return day;
}
class Stock {
int price;
int day;
public Stock(int price, int day) {
this.price = price;
this.day = day;
}
}
}
/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner obj = new StockSpanner();
* int param_1 = obj.next(price);
*/
方案二 利用数组+指针实现
第二种方式,采用两个数组,分别是prices用来记录股票价格和days用来记录跨度天数。那么针对第n次输入的股票,它的价格和跨度天数就是prices[n]和days[n]
除了prices和days这两个数组之外,我们还需要两个指针,分别是:
- index指针,用来指向“待输入股票”
- p指针,index指针的前一个指针,用来与“待输入股票”的price进行对比用的,如果它的price小于等于“待输入股票”的price,p就会向前移动
关于p向前移动的格子的数量,就是days的具体值;当days等于1时,就向前移动1个格子;如果days等于2时,就向前移动2个格子(因为days等于2,说明已经是两个格子聚合果的值了,就不需要重复统计了)。
public class StockSpanner {
int index = 0;
int[] prices, days;
public StockSpanner() {
prices = new int[10005];
days = new int[10005];
index = 0;
}
public int next(int price) {
int p = index - 1;
while (p >= 0 && prices[p] <= price) {
p -= days[p];
}
prices[index] = price;
days[index] = index - p;
return days[index++];
}
}
/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner obj = new StockSpanner();
* int param_1 = obj.next(price);
*/