理解动态规划

理解动态规划

题目:给定一个无序的数组,求此数组的最长递增子序列长度。
例如:list = [1,5,2,4,3],求此数组的最长递增序列长度。
一 暴力枚举/暴力搜索
我们可以列出可能出现的每一种情况,然后看这些可能的方案里,哪一种的子序列最长。
从1出发,就有以下几种状态:
从1出发此时,长度最长为3。
再从5出发,从2出发,等等等等,列举出各种情况之后,我们可以看到,最长的递增子序列为1,2,3或1,2,3。
可以使用递归来实现这一思路:

public int getMaxOrderedLength(int[] list){
        if(list.length<2){
            return list.length;
        }else{
            return getLength(list,0);
        }
    }

    private int getLength(int[] str,int i){
        if(i==str.length-1){
            return 1;//最少有一个字符
        }
        int length = 1;//在字符串长度大于1时,最小递增子序列长度为1
        for(int j=i+1;j<str.length;j++){
            if(str[i]<str[j]){
                length = Math.max(length,1+getLength(str,j));
            }
        }
        return length;
    }

对于一个长度为n的序列,时间复杂度为O(n2^n),因为对于序列中的每一个数,我们可以取,也可以不取,所以子序列数量为:
子序列
而对于每一个子序列,我们都会遍历一遍,所以总共的时间复杂度为:O(n
2^n),空间复杂度为1。
二 记忆化搜索/剪枝
在暴力搜索中,充满了大量的重复。比如运行到1,5时,我们就知道了5开始的最长递增子序列为1,但在后续运行到5时,我们又重复计算了5开始的最长递增子序列。为了避免多次重复计算。我们可以使用一个map或者其它的数据结构来记录这个结果。在运行时,先看是否已经记录了此数字的最长递增子序列,若已经记录,则直接返回。
动态规划正是因为避免了重复节点的计算,来加速整个计算过程。由于用到了数据结构来保存中间的计算结果,因此也称之为记忆化搜索。这也是动态规划以空间换时间的由来。也有人称这种操作为带备忘录的递归,或者递归树的剪枝,因为我们不需要再重复遍历节点。


    private int getLength(int[] str,int i,Map<Integer,Integer> map){
        if(map.containsKey(i)){
            return map.get(i);
        }
        if(i==str.length-1){
            map.put(i,1);
            return 1;//最少有一个字符
        }
        int length = 1;//在字符串长度不为零时,最小长度为1
        for(int j=i+1;j<str.length;j++){
            if(str[i]<str[j]){
                length = Math.max(length,1+getLength(str,j,map));
            }
        }
        map.put(i,length);
        return length;
    }

三 动态规划
记忆化搜索/剪枝,使用递归的方式来实现,我们现在可以试着将递归改为非递归的方式。
索引:0 1 2 3 4
[1,5,2,4,3]
对于[1,5,2,4,3]这样一个子序列,L(0)的最长递增子序列是[5,2,4,3],[2,4,3],[4,3],[3]里最长的递增子序列加1。依次类推
L(0) = max{L(1), L(2), L(3), L(4)} +1;
L(1) = max{L(2), L(3), L(4)} +1
= max{}+1 (因为5大于后续所有数,不能构成递增条件)
L(2) = max{L(3), L(4)} +1;
L(3) = max{L(4)} +1
= max{L()} +1
L(4) = 1;
由公式可知,若从后往前求最大递增子序列,就可以直接把所有答案推算出来。
代码:

private static int getLength(int[] str){
        int max=0;
        Map<Integer,Integer> map = new HashMap();
        for(int i = str.length-1;i>=0;i--){
            int length = 0;
            for(int j = i+1;j<str.length;j++){
                if(str[i]<str[j]){
                    length = Math.max(length,map.get(j));
                }
            }
            map.put(i,length+1);
            max = Math.max(max,length+1);
        }
        return max;
    }

四 总结
对于动态规划题目,首先可以使用暴力搜索的方法来画出递归树,再使用数据结构存储重复的元素进行剪枝,最后将过程改为迭代形式,就可以得到一道题的动态规划解法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值