菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
75
0

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

原创
05/13 14:22
阅读数 572

题目

下一个更大的元素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<Integer> stack = new Stack<Integer>();
        Map<Integer, Integer> map = new HashMap<Integer, Integer>(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;
    }


    /**
     * 穷举的变种
     * <p>
     * example:
     * nums1:{4,1,2}
     * nums2:{1,3,4,2}
     * res:{}
     * m:{}
     * <p>
     * 数组m初始后的赋值结果:
     * m:{,0,3,1,4}
     * <p>
     * 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 - 位置)次比较
     * <p>
     * 对 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");
        }
    }
}

发表评论

0/200
75 点赞
0 评论
收藏