学习动态规划

学习动态规划

 

学习动态规划

 

学习动态规划

 

学习动态规划

 

学习动态规划

 

学习动态规划

 

 

学习动态规划

 

学习动态规划

 

学习动态规划

 

学习动态规划

 

/*
假设有三种硬币足够多  2,5,7,要求支付某一面额 花费最少的硬币
 */
public class NineChapter_01 {
    public static void main(String[] args) {
        System.out.println(findMinNum(39));
        System.out.println(findMinNumByDp(39));
    }

    //递归方法
    private static int findMinNum(int x) {
        if (x==0){ return 0; }
        int res = 10000000;   //边界条件与限制
        if (x>=2){res= Math.min(findMinNum(x-2)+1,res);}
        if (x>=5){res= Math.min(findMinNum(x-5)+1,res);}//最后一步  是是什么
        if (x>=7){res= Math.min(findMinNum(x-7)+1,res);}
        return res;
    }
/*
1.确定状态  ,解动态规划是需要看一个数组,数组的每个元素f[i]或者 f[i][j]代表什么
a.最后一步:最优策略中的最后一个决策
b.子问题
2.转移方程:设状态f[x]=最少用多少枚硬币拼出x,对于任意的X   f[x] = min{f[x-2]+1,f[x-5]+1,f[x-7]+1};
3.初始条件和边界情况  用转移方程计算不出来  需要自己定义,防止数组越界,还要给一个初始值
4.计算顺序  以一个怎么样的顺序进行计算
 */
    //动态规划,设状态f[x]=最少用多少枚硬币拼出x,对于任意的X
    // f[x] = min{f[x-2]+1,f[x-5]+1,f[x-7]+1};
    private static int findMinNumByDp(int x) {
        if (x==0){return 0;}
        int[] dp = new int[x+1];
        dp[0]=0;
        for (int i = 1; i <=x ; i++) {
            dp[i]=100000;  //先将所有的赋值为最大值
        }
        for (int i = 0; i <=x ; i++) {
            if (i>=2){dp[i]=Math.min(dp[i-2]+1,dp[i]);}
            if (i>=5){dp[i]=Math.min(dp[i-5]+1,dp[i]);}
            if (i>=7){dp[i]=Math.min(dp[i-7]+1,dp[i]);}
        }
        return dp[x];
    }
    //官方代码
    private static int findMinNumByDp(int[] A,int M) { //A是含有2,5,7,的数组  ,M是目标
        int[] dp=new int[M+1];
        int n=A.length;
        dp[0]=0;
        int i,j;
        for ( i = 1; i <=M ; i++) {
            dp[i]=Integer.MAX_VALUE;
            for ( j = 0; j <n ; j++) {
                if (i>=A[j]&&dp[i-A[j]]!=Integer.MAX_VALUE){//边界条件  无穷大不能加1
                    dp[i]=Math.min(dp[i-A[j]]+1,dp[i]);
                }
            }
            }
            if (dp[M]==Integer.MAX_VALUE){
            dp[M]=-1;
            }
            return dp[M];
        }
}

学习动态规划

 

学习动态规划

 

 

学习动态规划

 

学习动态规划

 

学习动态规划

学习动态规划

 

 

//给定m行n列的网格,有一个机器人从左上角(0,0)出发,每一步可以向下或者向右走一步
// 问有多少种不同的方式走到右下角

//计数形式的动态规划
/*
1.确定状态 右下角坐标为(m-1,n-1),那么前一步机器人一定是在(m-2,n-1)或者是(m-1,n-2)中过渡而来的
那么,如果机器人有x种方式从左上角走到(m-2,n-1)
         机器人有y种方式从左上角走到(m-1,n-2)
         则机器人有x+y种方式走到(m-1,n-1)
 子问题 :机器人现在有多少种方式从左上角走到(m-2,n-1) 和(m-1,n-2)

 顺序的定义和转移方程有关
 */
public class Test02 {
    public static void main(String[] args) {
        int[][]  arr = new int[8][9];
        System.out.println(walkByDp(arr));
        System.out.println(uniquePaths(8,9));
    }

    //我的代码  代码中有错误定义错了边界
    private static int walkByDp(int[][] arr) {
        if (arr==null){
            return 0;
        }
        int[][] dp =new int[arr.length+1][arr[0].length+1];  //这里不是+1  注意边界
        dp[arr.length][arr[0].length]=1;
        int m=arr.length;
        int n=arr[0].length;
        for (int i = 0; i <=m ; i++) {
            dp[i][0]=1;
        }
        for (int i = 0; i <n ; i++) {
            dp[0][i]=1;
        }
        dp[0][0]=0;
        for (int i = 0; i <=m ; i++) {
            for (int j = 0; j <=n ; j++) {
                if (i>=1&&j>=1)
                {
                    dp[i][j]=dp[i-1][j]+dp[i][j-1];
                }
            }
        }
        return dp[arr.length-1][arr[0].length-1];
    }
    //老师的代码
    public static int uniquePaths(int m,int n){
        int[][] dp = new int[m][n];
        for (int i = 0; i <m ; i++) {
            for (int j = 0; j <n ; j++) {
                if (i==0||j==0){dp[i][j]=1;}
                else {
                    dp[i][j]=dp[i-1][j]+dp[i][j-1];
                }
            }
        }
        return dp[m-1][n-1];
    }
}

 

学习动态规划

 

 

学习动态规划

 

 

学习动态规划

 

学习动态规划

 

学习动态规划

 

学习动态规划

学习动态规划

//存在性问题
    public boolean canJump(int[] arr){
        int n=arr.length;
        boolean dp[] =new boolean[n];
        dp[0]=true;//第一个点青蛙能跳到
        for (int i = 1; i <n ; i++) {
            dp[i]=false;
            for (int j = 0; j <j ; j++) {
                if (dp[j]&&j+arr[j]>=i){//该石头已经确认跳到,而且j+arr[j]能跳的值大于 i   dp[i]=true
                    dp[i]=true;
                    break;
                }
            }
        }
        return dp[n-1];
    }

 

乘积最大子序列

找出一个序列中乘积最大的连续子序列(至少包含一个数)。

样例

样例 1:

输入:[2,3,-2,4]
输出:6

样例 2:

输入:[-1,2,4,1]
输出:8
 //非动态规划版本
   // dp[i][j]=arr[i]*...arr[j]
    //dp[i][j]表示从i到j最大的连续数
    public static int maxProduct(int[] nums) {//0---n-1   1....n
        // write your code here
        int n=nums.length;
        int[][] dp= new int[n][n];
        for (int i = 0; i <n ; i++) {
            for (int j = i; j <n ; j++) {
                dp[i][j]=1;
                for (int k = i; k <=j ; k++) {
                    dp[i][j]*=nums[k];
                }
            }
        }
        int max=Integer.MIN_VALUE;
        for (int i = 0; i <n ; i++) {
            for (int j = i; j <n ; j++) {
                if (dp[i][j]>=max){
                    max=dp[i][j];
                }
            }
        }
        return max;
    }

    public int maxProduct2(int[] nums) {
        int n = nums.length;
        int max = nums[0];
        int ans;
        for(int i = 0;i < n;++i){
            ans = nums[i];
            if(ans > max)
                max = ans;
            if(i != n - 1){
                for(int j = i + 1;j < n;++j){
                    ans *= nums[j];
                    if(ans > max)
                        max = ans;
                }
            }
        }
        return max;
    }


    //非动态规划版本
    // dp[i][j]=arr[i]*...arr[j]
    //dp[i][j]表示从i到j最大的连续数
    public static int maxProductByDp(int[] nums) {//0---n-1   1....n
        if (nums==null||nums.length<1){
            return 0;
        }
        // write your code here
        int n=nums.length;
        int max=nums[0];
        int min=nums[0];
        int result =nums[0];
        //每有一个新的数字加入,最大值要么是当前最大值*新数,要么是当前最小值(负数)*新数(负数),要么是当前值。
        for (int i = 1; i <n ; i++) {
           int temp=max;
           max=Math.max(Math.max(max*nums[i],min*nums[i]),nums[i]);
           min=Math.min(Math.min(temp*nums[i],min*nums[i]),nums[i]);
           if (max>result){
               result = max;
           }
        }

        return result;
    }

    /*
1.确定状态  ,解动态规划是需要看一个数组,数组的每个元素f[i]或者 f[i][j]代表什么
a.最后一步:最优策略中的最后一个决策
b.子问题
2.转移方程:设状态f[x]=最少用多少枚硬币拼出x,对于任意的X   f[x] = min{f[x-2]+1,f[x-5]+1,f[x-7]+1};
3.初始条件和边界情况  用转移方程计算不出来  需要自己定义,防止数组越界,还要给一个初始值
4.计算顺序  以一个怎么样的顺序进行计算
*/