818. Race Car
文章目錄
- 1 題目理解
- 2 BFS
- 3 dp
- 3.1 基本情況
- 3.2 遞歸方程分析
- 3.2.1 先超過target再調(diào)頭
- 3.2.2 不超過target
- 4 說明
1 題目理解
先講規(guī)則。一輛小汽車停在位置0,并且方向朝向右側(cè),并且速度為1。小汽車每次可以選擇加速A,那加速一次,新的位置=原來位置+速度,并且新的速度=速度*2。小汽車也可以選擇掉頭。掉頭一次的話,新的位置=原來的位置,并且新的速度=如果原來速度>0,那就是-1,否則的話是1。
輸入:int target。
輸出:小汽車到達位置target最少需要幾次操作。
例子:
Example 1:
Input:
target = 3
Output: 2
Explanation:
最短的操作順序 是: “AA”.
汽車位置變化為: 0->1->3.
Example 2:
Input:
target = 6
Output: 5
Explanation:
最短的操作順序 是 “AAARA”.
汽車位置變化為 0->1->3->7->7->6.
題目分析思路來源于花花醬。
2 BFS
因為在每個位置上,有兩種操作。在每次操作后速度、位置會發(fā)生變化。一直變,直到走到終點。所以可以按照BFS求解。遇到的第一個位置為target,就是最短的操作。
這里有幾個關(guān)鍵點。
關(guān)鍵點1:如果相同的位置和速度已經(jīng)加入過隊列,那就不需要再次計算。
關(guān)鍵點2:如果在位置0,小汽車朝向右側(cè)一定比朝向左側(cè)用的操作最少。這個可以用反證法證明。
關(guān)鍵點3:小汽車向右走,可以超過target,但 不能超過2*target。否則操作數(shù)會更多。
當(dāng)然這個方法是不能AC的。
通過這個方法我們知道在同一位置可能有兩種狀態(tài):速度向右、速度向左。這提示我們在做動態(tài)規(guī)劃的時候可能需要維護二維數(shù)組。
3 dp
如果target=7,我們發(fā)現(xiàn)
| 起始 | 0 | 1 |
| 第1次A | 1 | 2 |
| 第2次A | 3 | 4 |
| 第3次A | 7 | 8 |
3.1 基本情況
如果target=2n?1target = 2^n-1target=2n?1,那么到達target的最少操作數(shù)是n。是dp中的基本情況。
3.2 遞歸方程分析
如果不是,則可能要考慮兩種情況。第一種情況是先走過5達到7,因為7的最少操作數(shù)可以直接求解,是基本情況。然后再調(diào)頭,需要走2個位置達到5。如果我們提前計算好了走距離2的最少操作數(shù),那就可以求解了。第二種情況是可能走到j(luò)=1,2,3,4,然后再走剩下的距離。操作數(shù)之和就是達到5的操作數(shù)。兩種情況求最小值就是答案。下面分別討論。
令dp[i][0]表示從0達到位置i并且速度朝右的最小操作數(shù)。dp[i][1]表示從0達到位置i并且速度朝左的最小操作數(shù)。
3.2.1 先超過target再調(diào)頭
例如上面到達7,再返回達到5的時候可能速度方向朝左,也可能朝右。
dp[7][0]=3,dp[7][1]=4。
達到7調(diào)頭,這時候操作數(shù)是4。
繼續(xù)走2個距離,這時候的操作數(shù)是dp[2][0],這個時候的方向是朝左的。也就是說dp[5][1]= 4 + dp[2][0]。為什么是dp[2][0]而不是dp[2][1]呢?dp[2][0]表示從0到達2,并且方向向右,又因為起始位置速度的方向也向右,所以可以認為走過2個位置,并且方向和起始方向相同的最少操作數(shù)是dp[2][0]。當(dāng)?shù)竭_7以后調(diào)頭,方向向左了,走過2個距離并且速度方向一致,那操作數(shù)就是dp[2][0]。
當(dāng)然dp[5][1],也可能是通過dp[2][1]獲得,這個時候需要再加一個轉(zhuǎn)向操作,所以dp[5][1]=4+dp[2][1]+1。兩者取最小值。dp[5][1] = 4 + min(dp[2][0],dp[2][1]+1)。
同理,可以推出dpp[5][0] = 4 + min(dp[2][1],dp[2][0]+1)。
推出一般情況就是:
l=2n?1?targetl=2^n-1-targetl=2n?1?target
dp[target][0]=n+1+min(dp[l][1],dp[l][0]+1)dp[target][0] = n +1 + min(dp[l][1],dp[l][0]+1)dp[target][0]=n+1+min(dp[l][1],dp[l][0]+1)
dp[target][1]=n+1+min(dp[l][0],dp[l][1]+1)dp[target][1] = n +1 + min(dp[l][0],dp[l][1]+1)dp[target][1]=n+1+min(dp[l][0],dp[l][1]+1)
3.2.2 不超過target
再參考上圖target=5,如果不超過5。
那我們可以先走距離1,到達1以后再走距離4。到達5。
我們也可以先走距離2,到達2以后再走距離3。到達5。
…
我們也可以先走距離4,到達4以后再走距離1。到達5。
我們先分析先走距離1,到達1以后再走距離4。到達5的情況。達到1,如果方向向右,則需要先 調(diào)頭,再調(diào)頭,然后走距離4。那么dp[5][0] = dp[1][0]+2 + dp[4][0]。達到1,如果方向向左,則需要先調(diào)頭,然后走距離4。那么dp[5][0] = dp[1][1]+1 + dp[4][0]。最終dp[5][0] = min(dp[1][1]+1,dp[1][0]+2) + dp[4][0]。
同理:dp[5][1] = min(dp[1][1]+1,dp[1][0]+2) + dp[4][1]。
最終代碼
class Solution {public int racecar(int target) {int[][] dp = new int[target+1][2];dp[0][0] = 0;dp[0][1] = 1;for(int i=1;i<=target;i++){int n = (int)Math.ceil(Math.log(i+1)/Math.log(2));if((1<<n) == i+1){dp[i][0] = n;dp[i][1] = n+1;}else{int left = ((1<<n)-1 - i);dp[i][0] = n+1+Math.min(dp[left][1],dp[left][0]+1);dp[i][1] = n+1+Math.min(dp[left][0],dp[left][1]+1);for(int j = 1;j<i;j++){int min = Math.min(dp[j][0]+2,dp[j][1]+1);dp[i][0] = Math.min(dp[i][0], min+dp[i-j][0]);dp[i][1] = Math.min(dp[i][1], min+dp[i-j][1]);}}}return Math.min(dp[target][0],dp[target][1]);} }4 說明
看到題目還是應(yīng)該拿著具體數(shù)值分析一下。在某一特定情況下是怎么到達目的地的。
總結(jié)
以上是生活随笔為你收集整理的818. Race Car的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [密码学基础][每个信息安全博士生应该知
- 下一篇: Simcenter Amesim 202