一開始的思路是,用一個二維數組 dp[i][j] 記錄從位置 i 是否可以到達位置 j ,然後再遍歷從最後一列起從後往前遍歷每一列,如果這一列存在 1 則說明該列對應的下標是可達的,繼續遍歷前一列,如果某一列的值全部爲0,說明該列對應的位置是不可達的,整體不可達,返回false,思來想去,覺得這個思路應該沒有太大的問題,可能內存不能達到要求,果然,提交後,用例只跑到了第70個,內存超出限制了。
class Solution { public boolean canJump(int[] nums) { // n 是行,m是列 int n = nums.length-1,m = nums.length; int dp[][] = new int[n][m]; // 因爲最後一個位置是終點,所以i從0到n-1個位置即可 for (int i = 0; i < n; i++) { for (int j = i+1; j <m; j++) { // 某個位置i上加上該位置上的值nums[i]如果大於等於j,則說明i上可以到達j dp[i][j] = i+nums[i]>=j?1:0; if (dp[i][j]==0) break; } } // 從最後一列開始,遍歷每一列的每一個行元素,求該列元素的 | for (int i = m-1; i >0 ; i--) { int result = 0; for (int j = 0; j < n; j++) { result |= dp[j][i]; } if (result==0){ return false; } } return true; } }
解析:
當 i = 0 時,nums[0] = 2 ,說明在 i= 0的位置可以移動2個單位,因此 當 j = 1 , 2 時 dp[i][j] =1;
當 i= 1 時,nums[1] = 1,說明在 i= 1的位置可以移動1一個單位,因此 dp[1][2] = 1
以此類推,最後得到一個dp二維數組
接着從最後一列往前遍歷,如果某一列的值全部爲0,說明該列對應的下標是不可達的。如下
下標爲3時,該列的值全部爲0,說明下標爲3這個位置不能達到。
(ps:這只是一個不成熟的思考方向,看看就好,用例只通過了70個,內存已經超出限制了,也不知道沒有內存的限制下,這個思路是否正確。)
後來想了想,換了一種寫法
class Solution { public boolean canJump(int[] nums) { int n = nums.length-1,end = nums.length-1; for (int i = n-1; i >=0 ; --i) { if (i+nums[i]>=end) end = i; } return end==0; } }
初始時,end = 5,for循環從數組倒數第二個位置(i=4)往前遍歷
此時有 i + nums[i] = 4+1 =5 >=end,因此在接下來的循環中,終點不再是5,而是 end = i= 4
(因此此時if條件成立,說明 在 位置 i = 4 時,是可以移動到終點end = 5 的,那麼接下來只要驗證,i = 4前面的位置,可以移動到 4 這個位置即可)
【如果終點end在某個位置 i 時 被驗證可達,則接下來只要驗證 i 之前的位置是否可以達到 i (end=i) 即可】
如果條件不成立,則終點不變,i 繼續往前。
最後for循環結束後,如果end = 0 說明可以到達,否則不行。
再有這個例子
i從4開始往前遍歷,當 i = 4、3、2、1 時都有 i+nums[i] <end = 5
當 i = 0時有 i +nums[0] = 5 >=end;
此時應該修改 end = i 即end = 0;
if i + nums[i] >= end 繼續驗證 i-1 +nums[i-1] >= i (end=i) else i-1 +nums[i-1] >= end