算法-下一个更大元素 I-LeetCode.496

题目

下一个更大的元素I

给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出-1。

思路

  • 暴力穷举,使用双层 for 循环,这也是我一开始的思路
  • 单调栈:单调栈就是栈内元素单调递增或者单调递减的栈,单调栈只能在栈顶操作
  • 穷举的变种,空间换时间

关键点

单调栈:维护一个自栈顶向下递减的栈,当遇到要压入的元素>栈顶元素时,就将栈顶元素弹出,直到要压入的元素<栈顶元素时,压入。

代码

/**
 * 给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。
 * nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出-1。
 */
public class N496 {

    /**
     * 暴力穷举
     *
     * @param nums1
     * @param nums2
     * @return
     */
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        int[] result = new int[nums1.length];
        for (int i = 0; i < nums1.length; i++) {
            boolean isFind = false;
            boolean isMatch = false;
            for (int j = 0; j < nums2.length; j++) {
                if (!isFind) {
                    if (nums1[i] == nums2[j]) {
                        isFind = true;
                    }
                } else {
                    if (nums1[i] < nums2[j]) {
                        result[i] = nums2[j];
                        isMatch = true;
                        break;
                    }
                }
            }
            if (!isMatch) result[i] = -1;
        }
        return result;
    }

    /**
     * 单调栈
     *
     * @param nums1
     * @param nums2
     * @return
     */
    public int[] nextGreaterElement2(int[] nums1, int[] nums2) {
        int[] result = new int[nums1.length];
        Stack stack = new Stack();
        Map map = new HashMap(nums2.length);

        for (int i = 0; i < nums2.length; i++) {
            /**
             * 栈不为空,并且栈顶元素比当前元素小
             */
            while (!stack.isEmpty() && stack.peek() < nums2[i]) {
                map.put(stack.pop(), nums2[i]);
            }
            stack.push(nums2[i]);
        }
        while (!stack.isEmpty()) {
            map.put(stack.pop(), -1);
        }

        for (int i = 0; i < nums1.length; i++) {
            result[i] = map.get(nums1[i]);
        }

        return result;
    }


    /**
     * 穷举的变种
     * 

* example: * nums1:{4,1,2} * nums2:{1,3,4,2} * res:{} * m:{} *

* 数组m初始后的赋值结果: * m:{,0,3,1,4} *

* m 存在的意义是将 num2 的 角标-值 的关系颠倒成 值-角标 存储,即 * num2:{0,1},{1,3},{2,4},{3,2} * m: {0, },{1,0},{2,3},{3,1},{4,2} * 目的在于在遍历 num1 时,我能立即知道这个值在 num2 中的位置,减少(num2.length - 位置)次比较 *

* 对 res 赋值的操作中的 j=m[nums1[i]] 的含义是:找到本次比较值在 num2 中的位置,目的在于减少比较次数 * * @param nums1 * @param nums2 * @return */ public int[] nextGreaterElement3(int[] nums1, int[] nums2) { int l1 = nums1.length; int l2 = nums2.length; int[] res = new int[l1]; int max = 0; for (int num : nums2) { max = Math.max(num, max); } int[] m = new int[max + 1]; for (int i = 0; i < l2; i++) m[nums2[i]] = i; for (int i = 0; i < l1; i++) { res[i] = -1; for (int j = m[nums1[i]]; j < l2; j++) { if (nums2[j] > nums1[i]) { res[i] = nums2[j]; break; } } } return res; } public static void main(String[] args) { N496 n496 = new N496(); int[] nums1 = {4, 1, 2}; int[] nums2 = {1, 3, 4, 2}; int[] ints = n496.nextGreaterElement(nums1, nums2); for (int t : ints) { System.out.print(t + "\t"); } } }

你可能感兴趣的:(java,算法)