1. 程式人生 > 其它 >leetcode - Next Greater Element I-III - Java

leetcode - Next Greater Element I-III - Java

技術標籤:LeetCode

遇到了一道Easy題,這個Easy在於解起來很好解,但最優解實在不好想(現在的我是真想不太出來,看題看少了,讀書讀少了):
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.

大致就是給定兩個陣列,其中A陣列中的元素都來自B陣列,且裡邊的元素都是獨一無二的,沒有重複的。返回A陣列中每一個當前元素在B陣列中的下一個比當前元素大的元素,如果沒有則為-1。

先來個自己寫的lj解法,暴力到不能再暴力:

    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        int[] ans = new int[nums1.length];
        Stack<Integer> s;
        int n = nums2.length;
        Arrays.fill(ans,-1);
        
        for (int i = 0; i < nums1.length; i++) {
            s = new Stack<>();
            for (int j = n - 1; j >= 0; j--) {
                s.push(nums2[j]);
            }
            int peek = s.peek();
            while (peek != nums1[i]) {
                s.pop();
                peek = s.peek();
            }
            while (!s.empty()){
                if((peek = s.peek()) > nums1[i]){
                    ans[i] = peek;
                    break;
                }
                s.pop();
            }
        }
        return ans;
    }

不想寫註釋了,自己的程式碼都看不下去了,我已經不想知道我把每個元素入棧出棧多少次了。

看一下大佬的解法:先說一下思路,大佬的解法只把nums2中的每個元素入棧/出棧了一次

  • 對於每一個數,都與棧中的上一個元素比較
    • 如果大於棧中的上一個元素,那麼這個元素就是上一個元素應該查到的結果,並且將其pop掉,存入map進行記錄;迴圈直到stack為空或者查到元素大於當前元素(這一步保證了棧中的元素是數值遞減的)
    • 如果棧中沒有值,或者小於棧中Top元素則壓入棧
  • 最後用nums1中的元素在map中進行查詢,替換結果
/**
 * 這個解法巧妙之處在於,利用了findNums中的所有元素都是nums的子元素,
 * 利用nums將所有的
 */
public class NextGreaterElementIDiss {

    public int[] nextGreaterElement(int[] findNums, int[] nums) {
        HashMap<Integer, Integer> map = new HashMap<>();
        Stack<Integer> stack = new Stack<>();
        for (int num : nums) {
            while (!stack.isEmpty() && stack.peek() < num){
                map.put(stack.pop(),num);
            }
            stack.push(num);
        }
        for (int i = 0; i < findNums.length; i++) {
            findNums[i] = map.getOrDefault(findNums[i],-1);
        }
        return findNums;
    }
}

What can I say?下邊又做了這個系列的II,當然也是用棧,並且棧中元素也絕對是遞減的,題目藐視在上一道題的基礎上做了修改:1.陣列中的元素可重複 2.在查詢時可迴圈查詢,比如[1,2,1] 返回[2,-1,2]。
思想:
1.這個迴圈查詢,最多迴圈一次,我們可以寫為把陣列複製一份放在後邊(抽象)
2.我們可以在stack中存放陣列下標,而非陣列中的元素,因為元素是有重複的

    public int[] nextGreaterElements(int[] nums) {
        Stack<Integer> stack = new Stack<>();
        int n = nums.length;
        int[] ans = new int[n];
        Arrays.fill(ans,-1);
        for (int i = 0; i < n * 2; i++) {
            while (!stack.isEmpty() && nums[stack.peek()] < nums[i % n]){
                ans[stack.pop()%n] = nums[i%n];
            }
            stack.push(i%n);
        }
        return ans;
    }

III:Given a positive integer n, find the smallest integer which has exactly the same digits existing in the integer n and is greater in value than n. If no such positive integer exists, return -1.

Note that the returned integer should fit in 32-bit integer, if there is a valid answer but it does not fit in 32-bit integer, return -1.

Example 1:

Input: n = 12
Output: 21

Example 2:

Input: n = 21
Output: -1

第三題就有點大不一樣了,給一個數字,在數字組成相同的情況下尋找比當前數大的最小的數。
思路:

  • 第一步還是將數字轉成陣列的形式
  • 如果一個數所有數字都是按從大到小排列,那麼同樣的數字再也找不出比該數字更大的數了
  • 想要找到比當前數大的最小數,就需要從低位開始找,直到找到一位小於後一位,這樣說明有比當前數更大的數,起碼兩者做交換就產生了一個更大的數
  • 但這可能並不是比當前數大的最小數,我們需要向低位找比當前位數大的最小數,做交換
    程式碼:
    public int nextGreaterElement(int n) {
        char[] number = (n + " ").toCharArray();
        int len = number.length,i,j;
        //找增序的陣列位置
        for (i = len - 1;i > 0;i--){
            if(number[i-1] < number[i]){
                break;
            }
        }
        //如果i=0則說明沒有比當前數更大的數
        if (i==0){
            return -1;
        }
        int x = number[i-1],smallest = i;
        for(j = i+1; j < len;j++){
            //去後面找最小的元素
            if(number[j] > x && number[j] < number[smallest]){
                smallest = j;
            }
        }
        char tmp = number[smallest];
        number[smallest] = number[i-1];
        number[i-1] = tmp;

        Arrays.sort(number,i,len);
        long val = Long.parseLong(new String(number));
        return val > Integer.MAX_VALUE ? -1 : (int)val;
    }