今天处理一下一系列题目:Next Greater Element系列。
Next Greater Element I
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.
问题一是基础,翻译一下是这样:两个数组nums1是nums2的子集,而且nums2中各个数字都不重复。然后要求找nums1中的数字在nums2中的位置以右,是否还有比这个数字更大的数,要是有保存下来,要是没有就是-1。
思路也比较清楚,第一个想法肯定是两次遍历,但是肯定是最差的想法,我也就没有写。第二个思路,因为提到nums2中每个数字不重复,很容易联想到map,所以这个思路就是用map记录nums2中每个元素的位置,然后nums1中的元素去找的时候起始点就比较明确了。代码如下:
1 class Solution { 2 public int[] nextGreaterElement(int[] nums1, int[] nums2) { 3 int[] res = new int[nums1.length]; 4 Map<Integer,Integer> map = new HashMap<>(); 5 for ( int i = 0 ; i < nums2.length ; i ++ ) map.put(nums2[i],i); 6 for ( int i = 0 ; i < nums1.length ; i ++ ){ 7 for ( int j = map.get(nums1[i]) ; j < nums2.length ; j ++ ){ 8 if ( nums2[j] > nums1[i] ) { 9 res[i] = nums2[j]; 10 break; 11 }else res[i] = -1; 12 } 13 } 14 return res; 15 } 16 }
运行时间3ms,击败99.95%的提交。应该是现在能优化的最优的方法了。
Next Greater Element II
Given a circular array (the next element of the last element is the first element of the array), print the Next Greater Number for every element. The Next Greater Number of a number x is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, output -1 for this number.
Example 1:
Input: [1,2,1] Output: [2,-1,2] Explanation: The first 1's next greater number is 2; The number 2 can't find next greater number; The second 1's next greater number needs to search circularly, which is also 2.
Note: The length of given array won't exceed 10000.
现在题目变了一下,翻译一下:给一个数组nums,这个数组是一个循环数组,也就是最后一个元素的下一个元素是第一个元素。要求找数组中每个元素的next greater element(定义和上面题目一样)。
第一个思路:根据循环数组的定义,我们可以再定义一个长度为nums.length*2的数组,然后问题就简单了。代码如下:
1 class Solution { 2 public int[] nextGreaterElements(int[] nums) { 3 int[] array = new int[nums.length*2]; 4 int[] res = new int[nums.length]; 5 for ( int i = 0 ; i < nums.length ; i ++ ) { 6 array[i] = nums[i]; 7 array[i+nums.length] = nums[i]; 8 } 9 for ( int i = 0 ; i < nums.length ; i ++ ){ 10 for (int j = i; j < array.length; j++) { 11 if (array[j] > nums[i]) { 12 res[i] = array[j]; 13 break; 14 } else{ 15 res[i] = -1; 16 } 17 } 18 } 19 return res; 20 } 21 }
运行时间46ms,击败74.06%提交。
Next Greater Element III
Given a positive 32-bit integer n, you need to find the smallest 32-bit integer which has exactly the same digits existing in the integer nand is greater in value than n. If no such positive 32-bit integer exists, you need to return -1.
Example 1:
Input: 12 Output: 21
Example 2:
Input: 21 Output: -1
现在问题又发生了变化,给一个32bit的整数n,要求在组成n的这些数字里面,一个greater element。比如:134,有很多种数字组织办法:134、143、314、341、413、431,那么就返回143。
首先想到的就是要对1、3、4这几个数字进行全排列,然后再找最近的最大数。代码如下:
1 class Solution { 2 int mintoplus = Integer.MAX_VALUE; 3 public int nextGreaterElement(int n) { 4 String s = String.valueOf(n); 5 char[] array = s.toCharArray(); 6 perm(array,n,0,array.length-1); 7 if ( mintoplus == Integer.MAX_VALUE ) return -1; 8 return n+mintoplus; 9 } 10 private void perm(char[] a,int n ,int cur, int end ){ 11 if ( cur == end ){ 12 int toplus; 13 try { 14 toplus = Integer.valueOf(String.valueOf(a)) - n; 15 if ( toplus > 0 ) mintoplus = Math.min(mintoplus,toplus); 16 }catch (Exception e){ 17 mintoplus = Integer.MAX_VALUE; 18 } 19 }else { 20 for ( int i = cur ; i <= end ; i ++ ){ 21 swap(a,cur,i); 22 perm(a,n,cur+1,end); 23 swap(a,cur,i); 24 } 25 } 26 } 27 private void swap(char[] s, int cur, int i) { 28 char c = s[cur]; 29 s[cur] = s[i]; 30 s[i] = c; 31 } 32 }
mintoplus变量用来保存全排列数字与n的最小差,perm函数递归实现全排列数的生成。结果运行时间高达437ms,好差的算法,分析一下原因,主要是进行全排列太浪费时间了,而且全排列得到的很多结果都是无用的,因此不能使用全排列的方法。
思路二:因为比一个数字且最近一定尽量发生在数字低位,比如1345的greater数是1354,只是十位和个位交换。所以不妨设想从低位到高位寻找。我们以15764321为例:
1、15764321从低位到高位寻找,找到5比7小,然后index记录5的位置;
2、对index+1——最后,也就是764321从后往前寻找第一个大于5的数字,也就是76,bigIndex记录6的位置;
3、交换index和bigIndex位置元素,数组变成16754321,这时候我们需要对754321从小到大排列;
4、将index+1到最后位置从小到大排列,注意到未排列之前是从大到小顺序,因此只要交换位置就行了。
以上就是完整的思路,整理代码如下:
1 class Solution { 2 public int nextGreaterElement(int n) { 3 String s = n + ""; 4 char[] array = s.toCharArray(); 5 int index = -1; 6 7 //下面的代码从低位到高位,寻找低位比高位大的位置。 8 for ( int i = array.length - 2 ; i >= 0 ; i -- ){ 9 if ( array[i] < array[i+1] ) { 10 index = i; 11 break; 12 } 13 } 14 if ( index == -1 ) return -1; 15 //下面的代码寻找index+1----array.length-1中元素比array[index]大的;因为index+1----array.length-1中元素数组是有序的,从大到小 16 int bigIndex = index+1; 17 for ( int i = array.length - 1 ; i > index ; i -- ){ 18 if ( array[i] > array[index] ){ 19 bigIndex = i; 20 break; 21 } 22 } 23 //交换元素位置 24 swap(array,index,bigIndex); 25 //将index+1----array.length-1中的元素从小到大排列 26 reverse(array,index+1,array.length-1); 27 long l = Long.valueOf(String.valueOf(array)); 28 return l > Integer.MAX_VALUE?-1: (int) l; 29 30 } 31 32 private void reverse(char[] array, int low, int high) { 33 //这里注意到,index+1----array.length-1中的元素是一个从大到小的排列,因此只要颠倒他们顺序就可以了 34 while ( low < high ){ 35 char c = array[low]; 36 array[low] = array[high]; 37 array[high] = c; 38 low++; 39 high--; 40 } 41 } 42 43 private void swap(char[] array, int start, int end) { 44 //实现start位置元素和end位置元素交换位置 45 char c = array[start]; 46 array[start] = array[end]; 47 array[end] = c; 48 } 49 50 }
没有用全排列,从低位到高位寻找的方法非常成功,运行时间2ms,击败99.70%的人。
来源:https://www.cnblogs.com/boris1221/p/9307917.html