问题描述
小C是一名股票交易员,最近他关注某只股票的价格波动。给定该股票连续N天的价格列表 stockPrices,你需要为小C生成一个新列表,每个位置的值表示从那天起至少需要等待多少天才能看到价格上涨。如果没有上涨的情况,则对应位置的值为0。
例如,对于股票价格列表 [33, 34, 14, 12, 16],从第一天价格 33 开始,价格上涨发生在第二天价格 34,所以输出 1。若某天之后不再有价格上涨,则输出 0。
思路
根据题目的描述,我们需要给出每支股票的状态,即最近的上涨天数,如果没有上涨,则状态为 0
类比于最近的上升气温,这道题我们同样可以使用单调栈的思路
我们可以准备一个栈,对于每天的股票
-
当栈为空时或者栈中股票大于当前股票时,我们将价格和天数压入栈中
-
如果当前栈中股票小于当前股票,弹出栈中所有小于当前股票的股票,其最近的上涨天数就是自己的到当前股票的天数
正确性的证明这里使用反证法:
如果当前股票不是最近的上涨的股票,那么在今天之前,一定有一只股票的价格大于等于当前股票,那支股票就会将所有小于自己的股票弹出,所以栈中股票一定要么是那支股票之后的股票,要么是金额大于那支股票的股票,与已知矛盾。所以当前股票一定是所有被弹出股票最近的上涨的股票
解题方法
维护一个数组,记录每支股票的最近上涨天数
维护一个栈,用来实现单调栈的功能
枚举给定股票每天的价格
-
如果当前栈为空或者栈顶价格大于当前股票价格:将当前价格和当前天数一并压入栈中
-
否则,首先循环弹出所有价格小于当前价格的股票,对每个弹出的价格,依次根据压入天数,计算上涨天数,记录在数组中;之后将当前价格压入栈中
给定股票所有价格遍历结束后,将栈中剩余的股票价格及天数全部弹出,并依次将对应的上涨天数记录更新为 0,最后返回答案数组
复杂度
时间复杂度:
O(N)
对于给定的股票,最多进栈一次出栈一次
空间复杂度:
O(N)
记录每支股票的出栈天数,长度与给定股票的数组长度相同
代码
import java.util.*;public class Main { public static int[] solution(int N, int[] stockPrices) { int[] ans = new int[stockPrices.length]; Deque<Integer[]> stack = new LinkedList<>(); for (int i = 0; i < stockPrices.length; i++) { if (stack.isEmpty() || stack.peekFirst()[1] >= stockPrices[i]) { stack.addFirst(new Integer[]{i, stockPrices[i]}); } else if (stockPrices[i] > stack.peekFirst()[1]) { while (!stack.isEmpty() && stockPrices[i] > stack.peek()[1]) { Integer[] peek = stack.pollFirst(); ans[peek[0]] = i - peek[0]; } stack.addFirst(new Integer[]{i, stockPrices[i]}); } } while (!stack.isEmpty()) { Integer[] peek = stack.pollFirst(); ans[peek[0]] = 0; } return ans; } public static void main(String[] args) { System.out.println(java.util.Arrays.equals(solution(5, new int[]{33, 34, 14, 12, 16}), new int[]{1, 0, 2, 1, 0})); System.out.println(java.util.Arrays.equals(solution(6, new int[]{45, 44, 46, 43, 42, 48}), new int[]{2, 1, 3, 2, 1, 0})); System.out.println(java.util.Arrays.equals(solution(3, new int[]{10, 9, 8}), new int[]{0, 0, 0})); }}