每日温度 & 下一个更大的元素

每日温度

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

方法一:从前往后遍历
递减栈(含相同元素)
栈中存的是元素的下标,栈中元素都还没找到大于它的
如果当前元素比栈顶元素大,那么说明栈顶元素找到了大于它的温度,将它出栈,直至栈为空或者栈顶元素不比当前元素大,再将当前元素入栈
如果栈为空,或者当前元素不比栈顶元素大,说明栈顶元素还没有找到比它大的,将当前元素入栈

public int[] dailyTemperatures(int[] T) {
    int[] ans = new int[T.length];
    Stack<Integer> stack = new Stack<>();
    for (int i = 0; i < T.length; i++) {
        while(!stack.isEmpty() && T[stack.peek()] < T[i]) {
            int index = stack.pop();
            ans[index] = i - index;
        }
        stack.push(i);
    }
    return ans;
}

方法二:从后往前遍历
栈中元素是当前位置右边的元素,在其中寻找能不能找到一个比它大的元素,找到的一定是第一个,将比它小的元素出栈

public int[] dailyTemperatures(int[] temperatures) {
    int n = temperatures.length;
    Stack<Integer> stack = new Stack<>();
    int[] res = new int[n];
    for (int i = n - 1; i >= 0; i--) {
        while (!stack.isEmpty() && temperatures[i] >= temperatures[stack.peek()]) {
            stack.pop();
        }
        res[i] = stack.isEmpty() ? 0 : stack.peek() - i;
        stack.push(i);
    }
    return res;
}

下一个更大元素 I

nums1 中数字 x下一个更大元素 是指 xnums2 中对应位置 右侧第一个x大的元素。

给你两个** 没有重复元素** 的数组 nums1nums2 ,下标从 0 开始计数,其中nums1nums2 的子集。

对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j]下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1

返回一个长度为 nums1.length 的数组ans作为答案,满足ans[i]是如上所述的 下一个更大元素

示例 1:

输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:

  • 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
  • 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
  • 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。

示例 2:

输入:nums1 = [2,4], nums2 = [1,2,3,4].

输出:[3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:

  • 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。
  • 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。

方法一:暴力

public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    int m = nums1.length, n = nums2.length;
    int[] res = new int[m];
    for (int i = 0; i < m; i++) {
        int j = 0;
        while (j < n && nums2[j] != nums1[i]) {
            j++;
        }
        j++;
        while (j < n && nums2[j] <= nums1[i]) {
            j++;
        }
        res[i] = j == n ? -1 : nums2[j];
    }
    return res;
}

方法二:单调栈+hash
先处理nums,得到每个元素第一个比它大的元素,然后由于元素不重复,使用hash表获得到nums1

public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    int m = nums1.length, n = nums2.length;
    int[] res = new int[m];
    Map<Integer, Integer> map = new HashMap<>();
    Stack<Integer> stack = new Stack<>();
    for (int i = 0; i < n; i++) {
        while (!stack.isEmpty() && nums2[stack.peek()] < nums2[i]) {
            map.put(nums2[stack.pop()], nums2[i]);
        }
        stack.push(i);
    }
    for (int i = 0; i < m; i++) {
        res[i] = map.getOrDefault(nums1[i], -1);
    }
    return res;
}

也可以从后往前遍历:

public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    int m = nums1.length, n = nums2.length;
    int[] res = new int[m];
    Map<Integer, Integer> map = new HashMap<>();
    Stack<Integer> stack = new Stack<>();
    for (int i = n - 1; i >= 0; i--) {
        while (!stack.isEmpty() && nums2[i] > stack.peek()) {
            stack.pop();
        }
        map.put(nums2[i], stack.isEmpty() ? -1 : stack.peek());
        stack.push(nums2[i]);
    }
    for (int i = 0; i < m; i++) {
        res[i] = map.get(nums1[i]);
    }
    return res;
}

下一个更大元素 II

给定一个循环数组 numsnums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素

数字 x下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1

示例 1:

输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

需要处理的是循环数组,注意到只遍历一次序列是不够的,例如序列 [2,3,1][2,3,1],最后单调栈中将剩余 [3,1],其中元素 [1] 的下一个更大元素还是不知道的。
一个朴素的思想是,我们可以把这个循环数组「拉直」,即复制该序列的前 n−1 个元素拼接在原序列的后面。这样我们就可以将这个新序列当作普通序列,用上文的方法来处理。而在本题中,我们不需要显性地将该循环数组「拉直」,而只需要在处理时对下标取模即可。

public int[] nextGreaterElements(int[] nums) {
    int n = nums.length;
    int[] res = new int[n];
    Arrays.fill(res, -1);
    Stack<Integer> stack = new Stack<>();
    for (int i = 0; i < 2 * n - 1; i++) {
        while (!stack.isEmpty() && nums[i % n] > nums[stack.peek()]) {
            res[stack.pop() % n] = nums[i % n];
        }
        stack.push(i % n);
    }
    return res;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容