题目地址:
https://leetcode.com/problems/next-greater-node-in-linked-list/
链表版本的求下一个更大元素。还是用单调栈。维护一个单调下降的栈,如果栈空或者栈顶元素大于等于下一个来的元素,就把下一个来的元素入栈;否则一旦遇到比栈顶元素更大的元素,就说明栈顶元素的下一个更大元素就是要来的这个,记录一下并pop栈顶,然后继续check,直到栈的单调性重新满足。
基本思路是上面这样的,然而这题与数组的不同的地方在于,如果栈里存放的是node的下标,就会造成因为没有random access而无法知道该下标对应的值是多少;如果存放值,就无法知道该值的下标是多少。这里我们有两个方案:
法1:用两个栈,一个存放下标,另一个存放值。代码如下:
import java.util.*;
class Solution {
public int[] nextLargerNodes(ListNode head) {
if (head == null) {
return new int[0];
}
// 先求一下链表长度
int len = 1;
ListNode cur = head;
while (cur.next != null) {
len++;
cur = cur.next;
}
// 初始化一个数组
int[] res = new int[len];
// 一个栈专门存放值,另一个专门存放下标
Deque<Integer> stackVal = new LinkedList<>();
Deque<Integer> stackInd = new LinkedList<>();
// 用一个变量记录一下链表每个node的下标
int ind = 0;
while (head != null) {
// 下面的逻辑就是很简单的单调栈的思路
while (!stackInd.isEmpty() && stackVal.peek() < head.val) {
res[stackInd.pop()] = head.val;
stackVal.pop();
}
stackInd.push(ind++);
stackVal.push(head.val);
head = head.next;
}
return res;
}
}
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
时空复杂度 O ( n ) O(n) O(n)。
法2:用一个ArrayList来存放链表的值。这样就解决了random access的问题。但需要注意的是,最后需要把没有下一个更大元素的值置零。
import java.util.*;
public class Solution {
public int[] nextLargerNodes(ListNode head) {
if (head == null) {
return new int[0];
}
// list专门存放链表的值,stack存放下标
List<Integer> list = new ArrayList<>();
Deque<Integer> stack = new LinkedList<>();
int ind = 0;
while (head != null) {
list.add(head.val);
while (!stack.isEmpty() && list.get(stack.peek()) < head.val) {
// 如果出现了更大元素,就直接把list的对应位置的数改成那个更大元素
list.set(stack.pop(), head.val);
}
stack.push(ind++);
head = head.next;
}
// 接下来有一些没有更大元素的元素,需要将它们置零
while (!stack.isEmpty()) {
list.set(stack.pop(), 0);
}
// 最后开一个数组用来返回
int[] res = new int[list.size()];
for (int i = 0; i < res.length; i++) {
res[i] = list.get(i);
}
return res;
}
}
时空复杂度 O ( n ) O(n) O(n)。