问题:
You are given two arrays (without duplicates) nums1
and nums2
where nums1
’s elements are subset of nums2
. Find all the next greater numbers for nums1
's elements in the corresponding places of nums2
.
The Next Greater Number of a number x in nums1
is the first greater number to its right in nums2
. If it does not exist, output -1 for this number.
Example 1:
Input: nums1 = [4,1,2], nums2 = [1,3,4,2]. Output: [-1,3,-1] Explanation: For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1. For number 1 in the first array, the next greater number for it in the second array is 3. For number 2 in the first array, there is no next greater number for it in the second array, so output -1.
Example 2:
Input: nums1 = [2,4], nums2 = [1,2,3,4]. Output: [3,-1] Explanation: For number 2 in the first array, the next greater number for it in the second array is 3. For number 4 in the first array, there is no next greater number for it in the second array, so output -1.
Note:
- All elements in
nums1
andnums2
are unique. - The length of both
nums1
andnums2
would not exceed 1000.
解决:
【注】题目给定两个数组num1、num2(没有重复),num1是num2的子集,找到num1中每一个数值在num2中右侧是否存在比它大的数,如果存在就返回右侧第一个比它大的值,否则,返回-1.
① 遍历子数组中的每一个数字,然后在原数组中找到这个数字,然后向右遍历,找到第一个大于该数字的数即可。耗时久。
class Solution { // 17ms
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
List<Integer> list = new ArrayList<>();
for (int i = 0;i < nums1.length ;i ++ ) {
int j = 0;
for (;j < nums2.length ;j ++ ) {
if(nums1[i] == nums2[j]) break; //找到位置
}
int k = 0;
for (k = j + 1;k < nums2.length ;k ++ ) { //从下一个位置开始查找第一个大于的值
if(nums2[k] > nums2[j]){
list.add(nums2[k]);
break;
}
}
if(k == nums2.length) list.add(-1);
}
int[] res = new int[list.size()];
for (int i = 0;i < list.size() ;i ++ ) {
res[i] = list.get(i);
}
return res;
}
}
② 我们用HashMap先来建立每个数字和其坐标位置之间的映射,那么我们在遍历子数组中的数字时,就能直接定位到该数字在原数组中的位置,然后再往右边遍历寻找较大数即可。
class Solution { //9ms
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
List<Integer> list = new ArrayList<>();
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0;i < nums2.length ;i ++ ) {
map.put(nums2[i],i);
}
for (int i = 0;i < nums1.length ;i ++ ) {
int start = map.get(nums1[i]);
int j = 0;
for (j = start + 1;j < nums2.length ;j ++ ) {
if(nums2[j] > nums1[i]){
list.add(nums2[j]);
break;
}
}
if(j == nums2.length) list.add(-1);
}
int[] res = new int[list.size()];
for (int i = 0;i < list.size() ;i ++ ) {
res[i] = list.get(i);
}
return res;
}
}
③ 使用HashMap和栈,但是这里的HashMap和上面的不一样,这里是建立每个数字和其右边第一个较大数之间的映射,没有的话就是-1。利用栈来为nums2中的每个数字分配下一个最大值。(栈确实能达到此类效果)。
- 【 栈的特性 】正常循环的情况下,数组的滚动(游标移动)是向后的,引入栈的时候,则可以有了向前滚动的机会(有了一定的反悔的机会),然后这样子就能够解决一些局部的问题(比如说,寻找相邻的大的数字)。由于栈还可以对于没有价值(已经发现了大的数字)的东西删除,这样子的遗忘功能,简化了搜索空间,问题空间。
class Solution { // 19ms
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
List<Integer> list = new ArrayList<>();
Map<Integer,Integer> map = new HashMap<>();
Stack<Integer> stack = new Stack<>();
for (int n : nums2){
while(! stack.isEmpty() && stack.peek() < n){
map.put(stack.peek(),n);
stack.pop();
}
stack.push(n);
}
for (int n : nums1) {
list.add(map.getOrDefault(n,-1));
}
int[] res = new int[list.size()];
for (int i = 0;i < list.size() ;i ++ ) {
res[i] = list.get(i);
}
return res;
}
}
④ 在discuss中效率最高的解法,使用hash table保存数值和其下表之间的映射关系。
class Solution { // 10ms
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int max = -1;
for(int num : nums2){
if(num > max) max = num;
}
int[] hash = new int[max + 1];
for(int i = 0; i < nums2.length; i ++) {
hash[nums2[i]] = i;
}
int[] res = new int[nums1.length];
int count = 0;
for(int num : nums1) {
int index = hash[num] + 1;
res[count] = -1;
while(index < nums2.length) {
if(nums2[index] > num) {
res[count] = nums2[index];
break;
}
index ++;
}
count ++;
}
return res;
}
}