Java 算法 - 跳躍游戲(貪心法和動(dòng)態(tài)規(guī)劃)

注意,貪心法是錯(cuò)誤的!貪心法在lintCode能夠AC,leetCode不能AC。因?yàn)檫@道題是一道最優(yōu)題,而貪心法不能保證最優(yōu)

題意:

給出一個(gè)非負(fù)整數(shù)數(shù)組,你最初定位在數(shù)組的第一個(gè)位置。   

數(shù)組中的每個(gè)元素代表你在那個(gè)位置可以跳躍的最大長(zhǎng)度?!   ?
判斷你是否能到達(dá)數(shù)組的最后一個(gè)位置。

樣例:

A = [2,3,1,1,4],返回 true.

A = [3,2,1,0,4],返回 false.

注意事項(xiàng):

這個(gè)問題有兩個(gè)方法,一個(gè)是貪心和 動(dòng)態(tài)規(guī)劃。

貪心方法時(shí)間復(fù)雜度為O(N)。

動(dòng)態(tài)規(guī)劃方法的時(shí)間復(fù)雜度為為O(n^2)。

我們手動(dòng)設(shè)置小型數(shù)據(jù)集,使大家可以通過測(cè)試的兩種方式。這僅僅是為了讓大家學(xué)會(huì)如何使用動(dòng)態(tài)規(guī)劃的方式解決此問題。如果您用動(dòng)態(tài)規(guī)劃的方式完成它,你可以嘗試貪心法,以使其再次通過一次

1.貪心法

??正如注意事項(xiàng)所說的,這道題有種解法。我們先來看看貪心法。

(1).解題思路

??貪心法的思路非常的簡(jiǎn)單,那就是,當(dāng)跳到一個(gè)位置上,我們?cè)诋?dāng)前位置到當(dāng)前位置能達(dá)到的最大位置范圍找到最大值,如果最大值的index + 最大值大于當(dāng)前位置能達(dá)到的最大位置的index,那么選擇跳到最大值的index去,反之則跳到當(dāng)前位置能達(dá)到的最大位置。

(2).代碼

    public boolean canJump(int[] A) {
        //當(dāng)前跳的位置
        int index = 0;
        while (index < A.length - 1) {
            if (A[index] == 0) { // 如果當(dāng)前的值為0,就跳不動(dòng)了,那么肯定為false
                return false;
            }
            //最大值
            int max = Integer.MIN_VALUE;
            //最大值的index
            int maxIndex = 0;

            for (int i = index + 1; i < A.length && i < index + A[index]; i++) {
                if (max < A[i]) {
                    max = A[i];
                    maxIndex = i;
                }
            }
            //如果最大值和最大值的index的和大于當(dāng)前index + A[index]
            //表示下次調(diào)到最大值的位置上去
            if (maxIndex + max > index + A[index]) {
                index = maxIndex;
            } else {
                //反之則跳到index + A[index]
                index = index + A[index];
            }
        }
        return true;
    }

2.動(dòng)態(tài)規(guī)劃

(1).解題思路

??說實(shí)話,自己的動(dòng)態(tài)規(guī)劃還是很弱,有待加強(qiáng)!
??動(dòng)態(tài)規(guī)劃的思路相對(duì)來說要復(fù)雜一下,我們這里分兩種情況來討論
??第一步,定義一個(gè)dp一維數(shù)組,用來記錄每個(gè)位置是否能夠達(dá)到終點(diǎn)。比如,dp[i],表示在i位置,是否能夠跳到終點(diǎn),如果能,為true;反之為false。
??第二步,dp[i]是否能夠跳到終點(diǎn),這里主要分為兩種情況:
??1.如果當(dāng)前位置可以直接跳到終點(diǎn),也就是說i + A[i] >= A.length() - 1,那么直接讓dp[i] 為true就行了。
??2.如果當(dāng)前位置不能直接跳到終點(diǎn),但是可以借助其他位置跳到終點(diǎn),那么dp[i]也為true。這里設(shè)置為true有兩個(gè)條件,假設(shè)它借助j位置,首先dp[j]必須true,其次它必須能夠跳到j(luò)位置,也就是說i + dp[i] >= j。
??經(jīng)過簡(jiǎn)單的分析,應(yīng)該能夠理解到這個(gè)解法的思路吧?。?!

(2).代碼

    public boolean canJump(int[] A) {
        //dp數(shù)組表示當(dāng)前的位置是否能夠跳到最后
        boolean dp[] = new boolean[A.length];
        //默認(rèn)最后一個(gè)為true
        dp[A.length - 1] = true;
        for (int i = A.length - 2; i >= 0; i--) {
            //如果當(dāng)前位置能夠直接跳到終點(diǎn),直接設(shè)置為true
            if (i + A[i] >= A.length - 1) {
                dp[i] = true;
            }
            for (int j = i; j < A.length - 1; j++) {
                //設(shè)置為true的條件是:
                //1.借助的j點(diǎn)必須為true
                //2.必須能夠跳到j(luò)點(diǎn)來(i + A[i] >= j)
                if (dp[j] && i + A[i] >= j) {
                    dp[i] = true;
                }
            }
        }
        return dp[0];
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 動(dòng)態(tài)規(guī)劃(Dynamic Programming) 本文包括: 動(dòng)態(tài)規(guī)劃定義 狀態(tài)轉(zhuǎn)移方程 動(dòng)態(tài)規(guī)劃算法步驟 最長(zhǎng)...
    廖少少閱讀 3,660評(píng)論 0 18
  • 回溯算法 回溯法:也稱為試探法,它并不考慮問題規(guī)模的大小,而是從問題的最明顯的最小規(guī)模開始逐步求解出可能的答案,并...
    fredal閱讀 14,020評(píng)論 0 89
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,929評(píng)論 0 33
  • 分治方法 將問題劃分成互不相交的子問題 遞歸地求解子問題 將子問題的解組合起來 動(dòng)態(tài)規(guī)劃(兩個(gè)要素:最優(yōu)子結(jié)構(gòu)、子...
    superlj666閱讀 592評(píng)論 0 0
  • 在頁面請(qǐng)求數(shù)據(jù)時(shí),多數(shù)情況需要在頁面退出時(shí)檢查請(qǐng)求是否響應(yīng)完成,如果沒有響應(yīng)或正在請(qǐng)求中,這時(shí)就需要將這些請(qǐng)求ca...
    SCLDev閱讀 523評(píng)論 0 0

友情鏈接更多精彩內(nèi)容