1. 程式人生 > 其它 >LeetCode 題解 —— 1654. 到家的最少跳躍次數

LeetCode 題解 —— 1654. 到家的最少跳躍次數

技術標籤:OJ題解# LeetCode題解LeetCode題解1654BFS

題目相關

題目連結

LeetCode 中國,https://leetcode-cn.com/problems/minimum-jumps-to-reach-home/

Problem Statement

有一隻跳蚤的家在數軸上的位置 x 處。請你幫助它從位置 0 出發,到達它的家。

跳蚤跳躍的規則如下:

它可以 往前 跳恰好 a 個位置(即往右跳)。
它可以 往後 跳恰好 b 個位置(即往左跳)。
它不能 連續 往後跳 2 次。
它不能跳到任何 forbidden 陣列中的位置。

跳蚤可以往前跳 超過 它的家的位置,但是它 不能跳到負整數 的位置。

給你一個整數陣列 forbidden ,其中 forbidden[i] 是跳蚤不能跳到的位置,同時給你整數 a, b 和 x ,請你返回跳蚤到家的最少跳躍次數。如果沒有恰好到達 x 的可行方案,請你返回 -1 。

Samples 1

輸入:forbidden = [14,4,18,1,15], a = 3, b = 15, x = 9
輸出:3
解釋:往前跳 3 次(0 -> 3 -> 6 -> 9),跳蚤就到家了。

Samples 2

輸入:forbidden = [8,3,16,6,12,20], a = 15, b = 13, x = 11
輸出:-1

Samples 3

輸入:forbidden = [1,6,2,14,5,17,4], a = 16, b = 9, x = 7
輸出:2
解釋:往前跳一次(0 -> 16),然後往回跳一次(16 -> 7),跳蚤就到家了。

資料範圍

  • 1 <= forbidden.length <= 1000
  • 1 <= a, b, forbidden[i] <= 2000
  • 0 <= x <= 2000
  • forbidden 中所有位置互不相同。
  • 位置 x 不在 forbidden 中。

題解報告

題目分析

LeetCode 官方將本題難度定為中等。讀完題目,本題求最短路徑,哪就可以使用 BFS 了。

難點

難點一

和標準 BFS 相比,本題有一個限制,那就是回跳不能連續兩次。

如何解決這個問題呢?很簡單,記錄一下上次動作。這樣我們就可以判斷了。我們可以定義如下的資料型別。

struct JUMP {
    int  pos;//位置
    bool act;//動作。false為向後跳,true向前跳

    JUMP(int _pos, bool _act) : pos(_pos), act(_act) {}
    JUMP() { pos=0; act=true; }
};

難點二

在如下的資料

[162,118,178,152,167,100,40,74,199,186,26,73,200,127,30,124,193,84,184,36,103,149,153,9,54,154,133,95,45,198,79,157,64,122,59,71,48,177,82,35,14,176,16,108,111,6,168,31,134,164,136,72,98]
29
98
80

卡了好久。原因是前後是不同的,一個點即可以是往前跳到的,也可以是往後跳到的。不能因為往前跳到了這個點,就不允許這個點以後不讓往後跳到了。

我的控制方法是在向後不控制 visit。這裡目前我也說不出一個所以然,再仔細查查資料。

難點三

也正是由於可以向後跳,使得我們需要控制向前跳的總次數。根據題目可知 x 的最大值是 2000,a 的最大值是 2000,因此 x+2a 是最大的位置,也就是 6000。操作了這個位置,肯定是到不了家的。

AC 參考程式碼

const int MAXN=6e3+4;
int cost[MAXN];

struct JUMP {
    int  pos;//位置
    bool act;//動作。false為向後跳,true向前跳

    JUMP(int _pos, bool _act) : pos(_pos), act(_act) {}
    JUMP() { pos=0; act=true; }
};

class Solution {
public:
    int minimumJumps(vector<int>& forbidden, int a, int b, int x) {
        if (0==x) {
            return 0;
        }

        //可見性控制
        vector<bool> visit(MAXN, false);
        for (int i=0; i<forbidden.size(); i++) {
            visit[forbidden[i]]=true;
        }

        queue<JUMP> q;
        q.push(JUMP(0, false));
        visit[0]=true;
        int cost=0;//價值

        while (false==q.empty()) {
            cost++;//下一跳價值
            
            int len=q.size();
            for (int i=0; i<len; i++) {
                //當前位置
                JUMP curr=q.front();
                q.pop();

                //向前跳
                int npos=curr.pos+a;
                if (npos<MAXN && false==visit[npos]) {
                    //判斷是不是終點
                    //合法性判斷
                    if (x==npos) {
                        return cost;
                    }                    
                    visit[npos]=true;
                    //加入佇列
                    q.push(JUMP(npos, false));
                }

                //向後跳
                npos = curr.pos-b;
                //合法性判斷
                if (npos>=0 && false==visit[npos] && false==curr.act) {
                    //合法性判斷
                    if (x==npos) {
                        return cost;
                    }
                    //visit[npos]=true;
                    //加入佇列
                    q.push(JUMP(npos, true));
                }
            }
        }
        return -1;
    }
};

時間複雜度

O(N)。

空間複雜度

O(N)。