問題 長さ
n のゼロインデックス整数配列 nums が与えられました。初期位置は nums[0] です。
各要素 nums[i] は、インデックス i から前方にジャンプする最大長を表します。つまり、nums[i] にいる場合、任意の nums[i + j] にジャンプできます。
0 <= j <= nums[i]
i + j < n は、
nums[n - 1] に到達するためのジャンプの最小数を返します。生成されたテスト ケースは nums[n - 1] に達する可能性があります。
例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
例 2:
输入: nums = [2,3,0,1,4]
输出: 2
ヒント:
1 <= nums.length <= 10^4
0 <= nums[i] <= 1000
問は nums[n-1] に到達することが保証されています
解決策 1: 動的プログラミング
コードはより直感的でわかりやすい
int jump(vector<int>& nums) {
vector<int> dp(nums.size(),INT_MAX);
int n=nums.size();
if (n <3) return n-1;
dp[0] = 0;
for (int i = 0; i <= n - 2; i++) {
if (nums[i] == 0) continue;
//j为下标 k为可跳跃的步数
for (int j = i + 1, k = 1; j < n && k <= nums[i]; j++, k++) {
dp[j] = min(dp[j], dp[i] + 1);
}
}
return dp[n - 1];
}
動的ルールは O(n^2) である必要がありますが、これは最適な方法ではありません
Solution 2: Greedy
//この質問は直感的に貪欲です.方法は、現在の位置からジャンプできる最も遠い位置を考えて、そこにジャンプすることです.//しかし、
この質問では、あなたができる最も遠い位置ではないかもしれません. jump to at the moment Optimal
//現在の最も遠い位置にジャンプすると、その位置でジャンプできるステップ数が非常に少なくなる可能性があるため
//そして、1 つのステップをスキップすることを選択した場合、ジャンプ先の位置は非常に遠くまでジャンプできる
//だからこの質問を考えてみてください貪欲なアプローチは、現時点でどれだけジャンプできるかを見て、そのステップにジャンプするだけではなく、//
ジャンプできる範囲内でジャンプできる場所を検討することです、および別のジャンプでどこまでジャンプできるか
//できます。最も遠くまでジャンプした位置が最適なソリューションです
//これが最終結果に影響しないのはなぜですか? このような問題がないのはなぜですか?
//なぜこれが局所最適なのですか? ネストされたチェックの追加レイヤーにすぎません. 違いは何ですか?
//これにより、最初に、上の最も遠い位置へのジャンプが必ずしも最適な問題ではないことが保証されるため、//第
二に、この質問は前提条件を与えられており、間違いなく最後までジャンプできるでしょう
//上記の決定を下付き文字で使用する場合i ポイントにジャンプすることにしました j
//つまり、j は必ずしもジャンプできる距離が最も遠いわけではありませんが、ジャンプできるすべての位置の中で、再びジャンプするのに最も距離が長いジャンプです
//j がジャンプできる場合in the next step たどり着いた点は全て行き止まり(ジャンプできるステップ数は0)
//すると、前の点iで選択できる全点の次のステップは行き止まり。ポイントは 100% 到達可能です 条件
//最も重要なことは、j が到達できる他の場所からジャンプしても、他の場所が到達できる場所に到達できない可能性があるということです。j は確実にジャンプできる //そして、ローカル最適条件が満たされ
ますそして、j から再び上記の決定を使用し始めます。これも同じ理由です
//i から次のジャンプ位置にジャンプするのは、j がジャンプできる最も遠い位置ではありませんが、j から再起動して上記の決定を使用することに注意してください//つまり、
j を選択して最も遠い位置にジャンプする場合、j は次の i になります。
int jump(vector<int>& nums) {
int n=nums.size(),sum=0,index=0;
if (n < 3) return n - 1;
while(1){
sum += 1;//sum存储最少跳跃次数 index存储当前下标
if (index + nums[index] >= n - 1) return sum;
int move = index;//move存储跳一次再跳一次能到达的最远下标
int next_index = index;//next_index存储下一次跳去哪里
for (int i = 1; i <= nums[index]; i++) {
if (index+i+nums[index + i] >= move) {//细节 这里大于要加"=" 否则[1,2,1,1,1]这个例子过不了
move = index +i+ nums[index + i];//没有=号 [10,9,8,7,6,5,4,3,2,1,1,0]也过不了 想想为什么
next_index = index + i;
}
}
index = next_index;
}
return sum;
}