Java 算法-Frog Jump(动态规划)

  做这个题时,看到题的标签是动态规划,就尝试着用动态规划来做。于是努力的填表,然后在求出动态方程,结果经过填表,方程没有求出来,反而用另一种方式做出来了,我反正不知道分到哪一类的算法里面去。

1.莫名的算法

(1).解题思路

  这个算法的思路是这样的,每个石头都用对应的Set集合,Set保存的是它前面哪些石头可以跳到这里来。其中Set里面保存的是一个类的对象,类的封装的是前一个石头和经过的步数。如图所示

Java 算法-Frog Jump(动态规划)_第1张图片

  经过图示还有一定的理解,但是一个东西要注意的是:就是每当我们遍历一个石头时,就要从这个石头的石头往回遍历看看那些石头可以跳到这里来,所以我们还需要去遍历那些石头的记录下步数,如果步数不合法的话,那么是不能加载当前石头的Set集合的, 如果合法的话,现在我们只需要将这个石头加进去就行,而不用继续去这个石头其他的步数,已经合法了,没必要再去遍历下去了。如果这里不注意这一点的话,会超时的!

public static boolean canCross(int[] stones) {
        if (stones.length == 1 && stones[0] == 0) {
            return true;
        }
        if (stones[1] != 1) {
            return false;
        }

        List> list = new ArrayList>();
        for (int i = 0; i < stones.length; i++) {
            list.add(new HashSet());
        }
        list.get(0).add(new Bean(0, 0));
        list.get(1).add(new Bean(0, 1));
        for (int i = 2; i < stones.length; i++) {
            for (int j = i - 1; j >= 0; j--) {
                for (Bean bean : list.get(j)) {
                    if ((stones[i] - stones[j] >= bean.unit - 1) && (stones[i] - stones[j] <= bean.unit + 1)) {
                        list.get(i).add(new Bean(stones[j], stones[i] - stones[j]));
                        //这个石头可以加入当前石头的路径中,所以没有必要再去遍历
                        break;
                    }
                }

            }
            if (list.get(i).size() == 0) {
                break;
            }
        }
        return list.get(stones.length - 1).size() != 0;
    }

2.动态规划

  动态规划不是推导出来,而是在别人的代码上加以理解,有了自己的想法。

(1).解题思路

  现在感觉上面的方法跟动态规划很类似,都是用二维表来记录(上面的方法用的是List>),而这里定义了一个二维数组,我们假设它为dp[][],一维长度是stones.length,二维长度也是stones.length。为什么长度都是一样的呢?首先我们用一维表示第几个石头,二维来表示经过几步是否到达这里,例如:dp[i][j]表示的意思是在第i个石头时,从上一个石头(不一定是第i-1个石头)经过k步是否能到达i,true表示能,false表示不能,这里就知道了一维为stones.length。那为什么二维也是stones.length长度呢?想一想,每次跳的步数必须是k - 1、k或者k步,有stones.length个石头,所以最大的步数stones.length(每次跳的时候都在上一次加1)。
  现在我们的关键是推导出来方程,我们还是先填表:


Java 算法-Frog Jump(动态规划)_第2张图片
public static boolean canCross(int[] stones) {
        if (stones.length == 1 && stones[0] == 0) {
            return true;
        }
        if (stones[1] != 1) {
            return false;
        }
        boolean [][] dp = new boolean[stones.length][stones.length];
        dp[0][0] = true;
        for(int i = 0; i < stones.length; i++){
            for(int j = 0; j < i; j++){
                int k = stones[i] - stones[j];
                if(k >= stones.length){  //因为最大的步数就是stones.length
                    continue;
                }
                //默认可以从j经过k步跳过来(如果j上次跳了k步,也就是说dp[j][k] = true)
                dp[i][k] = dp[j][k];
                //这里的两个if,我理解的是为了数组不越界
                if(k - 1 >= 0){
                    dp[i][k] = dp[i][k] || dp[j][k - 1];
                }
                if(k + 1 < stones.length){
                    dp[i][k] = dp[i][k] || dp[j][k + 1];
                }
                
            }
        }
        boolean flag= false;
        for(int i = 0; i < stones.length;i++){
            if(dp[stones.length - 1 ][i]){
                flag = true;
                break;
            }
        }
        return flag;
    }

你可能感兴趣的:(Java 算法-Frog Jump(动态规划))