这个题目我第一次看到太简单了吧,暴力就完事了,果不其然,时间复杂度很高,当然结果也是过了,没什么难度:
public int[] nextLargerNodes(ListNode head) {
List<Integer> result = new LinkedList<>();
while (head != null) {
ListNode p = head.next;
while (p != null) {
if (p.val > head.val) {
result.add(p.val);
break;
}
p = p.next;
}
if (p == null)
result.add(0);
head = head.next;
}
int[] finalResult = new int[result.size()];
for (int i = 0; i < finalResult.length; ++i) {
finalResult[i] = result.get(i);
}
return finalResult;
}
但是能看到这个题目是一个中等难度的题目,所以肯定不是这么简单的。而且在做的过程中我看到了结果中有很多重复的元素,所以真相只有一个:我不会!!!
其实我是思考了的,当然就是简单的思考,反正也是错了就不说了,直接看的答案。然后第一眼看上去有单调栈和动态规划,听于是还没看下面我就想先自己尝试重新写一次。当然动态规划我前一段刚学过并做了借个题目,于是先写动态规划。
动态规划
dp的递推公式为:
- if nums[i + 1] > nums[i] then dp[i] = nums[i + 1]
- if nums[i + 1] == nums[i] then dp[i] = dp[i + 1]
- else dp[i] = { 遍历 dp[i + 1] … dp[n],寻找最近大于 nums[i] 的值,遇到 0 停止遍历,遇到 0 表示后面没有更大的值了 }
public static int[] nextLargerNodes1(ListNode head) {
List<Integer> temp = new LinkedList<>();
ListNode p = head;
while (p != null) {
temp.add(p.val);
p = p.next;
}
int numLength = temp.size();
int[] nums = new int[numLength]; //存放所有数据的数组
nums[numLength-1] = temp.get(numLength-1);
int[] dp = new int[numLength]; //动态规划数组
dp[numLength-1] = 0;
int[] result = new int[numLength]; //存放最终结果的数组
for (int i = nums.length-2; i >= 0; --i) {
nums[i] = temp.get(i);
if(nums[i] < nums[i+1]) {
dp[i] = nums[i+1];
result[i] = nums[i+1];
} else if (nums[i] == nums[i+1]) {
dp[i] = dp[i+1];
result[i] = dp[i+1];
} else {
int j = i;
for (; j < numLength; ++j) {
if (nums[j] > nums[i]) {
dp[i] = nums[j];
result[i] = nums[j];
break;
}
}
if (j == numLength) {
dp[i] = 0;
result[i] = 0;
}
}
}
return result;
}
单调栈
单调栈的思路就是从前往后遍历,让栈内元素始终是递减的,如果遇到一个元素比栈顶大,说明不能满足递减,则把栈内所有比当前元素小的都出栈,且对应的result值就是当前元素。直到遇到一个比当前元素大的栈顶停止,并将当前元素入栈。
最后将所有栈内元素出栈,且对应的值全部设置为0。这里我们在栈内保存的有两个元素,一个是链表的值,一个是值所在的位置。
public int[] nextLargerNodes(ListNode head) {
//先统计一下有多少个元素
int numLenght = 0;
ListNode p = head;
while (p != null) {
numLenght++;
p = p.next;
}
int[] result = new int[numLenght];
//栈应该存放两个值,一个是节点值,一个是节点所处位置(下标,方便在result中设置值)
Stack<Pair<Integer, Integer>> stack = new Stack<>();
stack.push(new Pair<>(head.val, 0)); //放第一个元素的值,及对应的下标0
p = head.next;
int index = 1; //记录每个节点的位置
while (p != null) {
//如果大于栈顶,则把所有小于当前p的值出栈,并设置为p.val
while (!stack.isEmpty() && p.val > stack.peek().getKey()) {
Pair<Integer, Integer> curPair = stack.pop();
result[curPair.getValue()] = p.val; //result中对应下标设置为当前值
}
stack.push(new Pair<>(p.val, index));
p = p.next;
index++;
}
//将栈内剩余的元素出栈,并设置对应位置的值为0
while (!stack.isEmpty()) {
Pair<Integer, Integer> curPair = stack.pop();
result[curPair.getValue()] = 0;
}
return result;
}
好了,又get到了一些技能…