Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LeetCode] 975. Odd Even Jump #975

Open
grandyang opened this issue May 30, 2019 · 0 comments
Open

[LeetCode] 975. Odd Even Jump #975

grandyang opened this issue May 30, 2019 · 0 comments

Comments

@grandyang
Copy link
Owner

grandyang commented May 30, 2019

You are given an integer array A. From some starting index, you can make a series of jumps. The (1st, 3rd, 5th, ...) jumps in the series are called odd-numbered jumps, and the (2nd, 4th, 6th, ...) jumps in the series are called even-numbered jumps. Note that the jumps are numbered, not the indices.

You may jump forward from index i to index j (with i < j) in the following way:

  • During odd-numbered jumps (i.e., jumps 1, 3, 5, ...), you jump to the index j such that A[i] <= A[j] and A[j] is the smallest possible value. If there are multiple such indices j, you can only jump to the smallest such index j.
  • During even-numbered jumps (i.e., jumps 2, 4, 6, ...), you jump to the index j such that A[i] >= A[j] and A[j] is the largest possible value. If there are multiple such indices j, you can only jump to the smallest such index j.
  • It may be the case that for some index i, there are no legal jumps.

A starting index is good if, starting from that index, you can reach the end of the array (index A.length - 1) by jumping some number of times (possibly 0 or more than once).

Return  the number of good starting indices.

Example 1:

Input: A = [10,13,12,14,15]
Output: 2
Explanation:
From starting index i = 0, we can make our 1st jump to i = 2 (since A[2] is the smallest among A[1], A[2], A[3],
A[4] that is greater or equal to A[0]), then we cannot jump any more.
From starting index i = 1 and i = 2, we can make our 1st jump to i = 3, then we cannot jump any more.
From starting index i = 3, we can make our 1st jump to i = 4, so we have reached the end.
From starting index i = 4, we have reached the end already.
In total, there are 2 different starting indices i = 3 and i = 4, where we can reach the end with some number of
jumps.

Example 2:

Input: A = [2,3,1,1,4]
Output: 3
Explanation:
From starting index i = 0, we make jumps to i = 1, i = 2, i = 3:

During our 1st jump (odd-numbered), we first jump to i = 1 because A[1] is the smallest value in [A[1], A[2],
A[3], A[4]] that is greater than or equal to A[0].

During our 2nd jump (even-numbered), we jump from i = 1 to i = 2 because A[2] is the largest value in [A[2], A[3],
A[4]] that is less than or equal to A[1]. A[3] is also the largest value, but 2 is a smaller index, so we can
only jump to i = 2 and not i = 3

During our 3rd jump (odd-numbered), we jump from i = 2 to i = 3 because A[3] is the smallest value in [A[3], A[4]]
that is greater than or equal to A[2].

We can't jump from i = 3 to i = 4, so the starting index i = 0 is not good.

In a similar manner, we can deduce that:
From starting index i = 1, we jump to i = 4, so we reach the end.
From starting index i = 2, we jump to i = 3, and then we can't jump anymore.
From starting index i = 3, we jump to i = 4, so we reach the end.
From starting index i = 4, we are already at the end.
In total, there are 3 different starting indices i = 1, i = 3, and i = 4, where we can reach the end with some
number of jumps.

Example 3:

Input: A = [5,1,3,4,2]
Output: 3
Explanation:
We can reach the end from starting indices 1, 2, and 4.

Constraints:

  • 1 <= A.length <= 2 * 104
  • 0 <= A[i] < 105

这道题给了一个数组,可以在任意的位置进行跳跃,分为奇数跳跃和偶数跳跃。第一次跳跃就是奇数跳跃,第二次就是偶数,第三次又是奇数,以此类推。奇数跳跃时到达的位置上的数字必须要大于等于起跳位置的数字,若有多个位置的数字都大于等于起跳位置,选其中最小的,若数字相同,选坐标最小的。而偶数跳跃到达的位置上的数字必须要小于等于起跳位置的数字,若有多个位置的数字都小于等于起跳位置,选其中最大的,若数字相同,选坐标最小的。现在定义了一种好起点,需要能按照上面的跳跃方式到达数组最后一个位置,问有多少个这样的好起点。说实话,这道题的题目博主是看了好久才搞懂,看到论坛上也有人吐槽题意晦涩难懂的。不过点赞数远超踩的个数,看来还是一道不错的题目。由于起点是任意的,那么若起点就是在最后一个位置,则就不用跳了,所以结果 res 可以初始化为1。然后就可以往前推,对于前一个数字和当前数字的关系,实际上就是大于等于,或者小于等于,可以分别对应两种跳法,这样其实每个位置上就有两种状态,一种是能否跳到大于等于的位置,用 higher 表示,一种是能否跳到小于等于的位置,用 lower 表示。这样就可以用两个数组 higher 和 lower 表示,其中 higher[i] 表示起点为i位置,首先跳到大于等于的位置(奇数跳跃),看是否能跳到末尾位置,这个就是题目所要求的。lower[i] 表示起点为i位置,首先跳到小于等于的位置(偶数跳跃),看是否能跳到末尾位置。则最末尾的位置 higher[n-1] 和 lower[n-1] 都要初始化为 true。在往前推的时候,需要在后方的数字中找出第一个不小于当前数字的数,和第一个不大于当前数字的数,为了快速查找,可以使用 TreeMap 来建立数字和其下标之间的映射,然后就可以用 lower_bound 和 upper_bound 来快速的查找了。这里 lower_bound 是查找第一个不小于目标值的数,正好就是要求的,只要该数字存在,则可以用该数字的 lower 值来更新当前数字的 higher 值,因为奇数跳跃和偶数跳跃是要交替进行的。这里的 upper_bound 是查找第一个大于目标的数,其往前退一位就是第一个不大于目标的数,但是在退之前,要先确定这不是第一个数字,否则没法往前退。用查找到的数字的 higher 值来更新当前数字的 lower 值。每次若 higher 值为 true,则结果 res 自增1,参见代码如下:

class Solution {
public:
    int oddEvenJumps(vector<int>& A) {
        int res = 1, n = A.size();
        vector<bool> higher(n), lower(n);
        higher[n - 1] = lower[n - 1] = true;
        map<int, int> num2idx;
        num2idx[A[n - 1]] = n - 1;
        for (int i = n - 2; i >= 0; --i) {
            auto hi = num2idx.lower_bound(A[i]), lo = num2idx.upper_bound(A[i]);
            if (hi != num2idx.end()) higher[i] = lower[hi->second];
            if (lo != num2idx.begin()) lower[i] = higher[(--lo)->second];
            if (higher[i]) ++res;
            num2idx[A[i]] = i;
        }
        return res;
    }
};

Github 同步地址:

#975

参考资料:

https://leetcode.com/problems/odd-even-jump/

https://leetcode.com/problems/odd-even-jump/discuss/217974/Java-solution-DP-%2B-TreeMap

https://leetcode.com/problems/odd-even-jump/discuss/217981/JavaC%2B%2BPython-DP-using-Map-or-Stack

LeetCode All in One 题目讲解汇总(持续更新中...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant