给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
注意: 输入数组的长度不会超过 10000。
通过此题掌握JAVA中栈的使用
题目分析:此题和下一个更大的元素I最大的区别就是——此题给定的数组可以循环访问,直至访问到下一个更大的元素为止;
循环访问数组的最好处理就是将访问长度设为数组的两倍,并用取余操作处理;
刚开始我仿照下一个更大的元素I利用hashMap()处理,代码如下:
class Solution { public int[] nextGreaterElements(int[] nums) { Stack<Integer> stack = new Stack<>(); HashMap<Integer,Integer> hashMap = new HashMap<>(); int size = nums.length; for (int i = 0; i < size * 2; i++) { int num = nums[i % size]; while (!stack.isEmpty() && stack.peek() < num) { hashMap.put(stack.pop(),num); } stack.push(num); } int[] res = new int[nums.length]; for (int i = 0; i < nums.length; i++) { res[i] = hashMap.getOrDefault(nums[i], -1); } return res; } }
但是运行结果出错:
之后发现是因为哈希表中键与值的关系只能是1对1或多对1,如果出现1对多的情况,前面键对应的值就会被覆盖,出现冲突,所以此题用哈希表去解决就要去处理冲突,这就可能会将问题变得更复杂,行不通。
最后仔细一想,刚开始栈中存储的是数组中的元素,进行比较的时候是两个值去比较,找出比栈顶大的元素存入;但是我们在栈中如果存储的是数组中元素的下标,那么就不会出现覆盖的问题,这样就慢慢的找到了解决方法。
代码实现:
public int[] nextGreaterElements(int[] nums) { Stack<Integer> stack = new Stack<>(); int size = nums.length; int[] res = new int[size]; Arrays.fill(res,-1); for (int i = 0; i < size * 2; i++) { int num = nums[i % size]; while (!stack.isEmpty() && nums[stack.peek()] < num) { res[stack.pop()] = num; } if (i < size) stack.push(i); } return res; }
算法详解:
以主函数中的数组[100,1,11,1,120,111]为例:
找了很久才找到JAVA中给数组赋初值的函数Arrays.fill();
- 刚开始数组res = [-1, -1, -1, -1, -1, -1]
- 进入for循环,num = nums[0] = 100
- i < size, 把此时的i压栈,此时stack = [0]
- num = nums[1] = 1
- 栈不空,进入while循环,nums[stack.peek()] = nums[0] = 100 > 1
- i < size, 把此时的i压栈,此时stack = [0,1]
- num = nums[2] = 11
- 栈不空,进入while循环,nums[stack.peek()] = nums[1] = 1 < 11
- res[stack.pop()] = res[1] = 11,此时数组res = [-1, 11, -1, -1, -1, -1]
- 栈不空,进入while循环,nums[stack.peek()] = nums[0] = 100 > 11
- i < size, 把此时的i压栈,此时stack = [0,2]
- num = nums[3] = 1
- 栈不空,进入while循环,nums[stack.peek()] = nums[2] = 11 > 1
- i < size, 把此时的i压栈,此时stack = [0,2,3]
- num = nums[4] = 120
- 栈不空,进入while循环,nums[stack.peek()] = nums[3] = 1 < 120
- res[stack.pop()] = res[3] = 120,此时数组res = [-1, 11, -1, 120, -1, -1]
- 栈不空,进入while循环,nums[stack.peek()] = nums[2] = 11 < 120
- res[stack.pop()] = res[2] = 120,此时数组res = [-1, 11, 120, 120, -1, -1]
- 栈不空,进入while循环,nums[stack.peek()] = nums[0] = 100 < 120
- res[stack.pop()] = res[0] = 120,此时数组res = [120, 11, 120, 120, -1, -1]
- 栈空,退出while循环
- i < size, 把此时的i压栈,此时stack = [4]
- num = nums[5] = 111
- 栈不空,进入while循环,nums[stack.peek()] = nums[4] = 120 > 111
- i < size, 把此时的i压栈,此时stack = [4,5]
- 之后便进入了第二次遍历数组,过程一样,去循环找到下一个更大的数,只是此时不再把i入栈
- 找到nums[stack.peek()] = nums[5] = 111 < 120
- res[stack.pop()] = res[5] = 120,此时数组res = [120, 11, 120, 120, -1, 120]
- 最后栈stack = [4],找不到比120更大的数
- for循环结束
- 最后结果就是数组res = [120, 11, 120, 120, -1, 120]
主函数:
public static void main(String[] args) { T4 t4 = new T4(); int[] a = t4.nextGreaterElements(new int[]{100, 1, 11, 1, 120, 111}); for (int i = 0; i < a.length; i++) { System.out.print(a[i] + " "); } }
运行结果:
120 11 120 120 -1 120