力扣跳跃问题,起初使用动态规划做,即从末尾开始确定能够到达最后一格的位置,类似于动态规划的做法,与跳台阶,斐波那契数列有异曲同工之妙。
自己写的代码,又臭又长,效率嘎嘎烂
class Solution {
public boolean canJump(int[] nums) {
int right=nums.length-1;
int left=right-1;
if(nums.length==1){//如果说数列只有一个数,直接return true
return true;
}
return dfs(nums,left,right);
}
public boolean dfs(int[] nums,int left,int right){
//定义函数,right表示子数列末尾,left表示有可能到达子数列末尾的数组元素下标
if(left<0){
return false;
}
if(nums[left]<(right-left)){
left--;
}
else if(nums[left]>=(right-left)){
right=left;
left--;
}
if(right==0){//到达数组开头,正确
return true;
}
return dfs(nums,left,right);//未到达开头,继续逆向遍历
}
}
贪心算法使用
遍历数组元素每一个下标,去探求它们所能到达的最远处,如果能到达最远处,则返回true
它是正序遍历的。也是相当于将数组分成多段路径,每一步去探求它最大能走到哪里,在这个路径范围里,继续去探求路径内的元素最大可以走到哪里,以此类推,看它是否能够走到数组的末尾。
public class Solution {
public boolean canJump(int[] nums) {
int n = nums.length;
int rightmost = 0;
for (int i = 0; i < n; ++i) {
if (i <= rightmost) {//子路径的最远距离范围
rightmost = Math.max(rightmost, i + nums[i]);//保留了最远距离
if (rightmost >= n - 1) {
return true;
}
}
}
return false;
}
}
我再接着了解了一下什么是贪心算法
贪心算法的基本要素:
1.贪心选择性质。所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。
动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。
个人感觉就是动态规划基本是倒着推,类似于数学归纳法。贪心算法是正着推,每一步寻求局部最优,以做到全部最优。
对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
2. 当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用动态规划算法或贪心算法求解的关键特征。
跳跃游戏二,进行了一个小小的变形,不过从这一题我发现我理解的并不透彻
这题将贪心算法更透彻地显示出来,就是算出区域内的最优解,要注意的是,这个区域是一直在动态更新的(最大覆盖区域),当i等于这个动态区域的时候,更新这个区域范围(当前覆盖的最大区域)
class Solution {
public int jump(int[] nums) {
if (nums == null || nums.length == 0 || nums.length == 1) {
return 0;
}
//记录跳跃的次数
int count=0;
//当前的覆盖最大区域
int curDistance = 0;
//最大的覆盖区域
int maxDistance = 0;
for (int i = 0; i < nums.length; i++) {
//在可覆盖区域内更新最大的覆盖区域
maxDistance = Math.max(maxDistance,i+nums[i]);
//说明当前一步,再跳一步就到达了末尾
if (maxDistance>=nums.length-1){
count++;
break;
}
//走到当前覆盖的最大区域时,更新下一步可达的最大区域
if (i==curDistance){
curDistance = maxDistance;
count++;
}
}
return count;
}
}