动态规划——在做题中理解你的美

一、求数组最大子数组和
子数组必须是连续的,数组中可能包含有:正整数,零,负整数三种中的一种或多种。
方法一:可以用普通的方法枚举所有的连续子数组,然后求出最大的子数组和,时间复杂度为O(n*n)。
方法二:动态规划!
方法一代码:

int MaxSubString(int[] A, int n)
{
  int max = min;  //初始值为负无穷大
  int sum;
  for(int i = 0; i < n; i++)
  {
    sum = 0;
    for(int j = i; j < n; j++)
    {
      sum += A[j];
      if(sum > max)
        max = sum;
    }
  }
  return max;
}

方法二代码:


import java.util.Scanner;

public class BigSubArraySum {
    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);
        System.out.println("请输入n个整数");
        int n = input.nextInt();
        int[] arr = new int[n];

        for (int i = 0; i < n; i++) {
            arr[i] = input.nextInt();
        }

        int max = arr[0];
        int currentMax = arr[0];

        for (int i = 1; i < arr.length; i++) {

            //currentMax = (currentMax >= 0) ? arr[i] + currentMax : arr[i];

            currentMax = Math.max(arr[i] + currentMax,arr[i]);
            max = Math.max(max, currentMax);

        }
        System.out.println(max);
    }
}

数组: {0, -2, 3, 5, -1, 2} 返回值为 9,因为连续子数组3+5-1+2=9>3+5=8;

二、硬币问题
(还是有问题,当货币中为2,3,4或者其他就会出现bug,待解决)

public class MinCoins {

    public static void main(String[] args) {

        int[] coins = {1,3,5};      //coins数组存放各个无重复面值
        int value = 17;                 //value表示需要凑成的钱数
        int[] jilu = new int[value];    //记录每一步的面值
        int min = new MinCoins().solution(coins, value, jilu);
        for (int i = value - 1; i >= 0;) {
            System.out.print(jilu[i] + "->");
            i = i - jilu[i];//倒序输出每一步用的哪种币
        }
        System.out.println();
        System.out.println(min);

    }

    private int solution(int[] coins, int value, int[] jilu) {

        int[] mins = new int[value + 1];    //数组mins表示凑成多少钱所需最小钱币数目,为了使索引能达到value,加1

        mins[0] = 0;                        //凑成0元所需0个

        for (int i = 1; i <= value; i++)    //将数组中的数初始化为最大值
            mins[i] = Integer.MAX_VALUE;


        for (int i = 1; i <= value; i++) {  //从凑1元钱开始,递增直至value

            for (int j = 0; j < coins.length; j++) {//j表示第(j+1)种币

                if (coins[j] <= i) {  

                    //意思是比较所有种类的币是不是比所要凑的值小,
                    //如若比要凑得值还大就跳过比下一种币

                    mins[i] = Math.min(mins[i] , mins[i - coins[j]] + 1);
                    //将满足coins[j] <= i的coins[j]遍历一遍,则mins[i]存储的值就是几种情况中的最小值
                    jilu[i - 1] = coins[j];//记录每步所使用的币值
                }

            }

        }
        return mins[value];
    }

}

三、背包问题
w[i] : 第i个物体的重量;
p[i] : 第i个物体的价值;
arr[i][m] : 前i个物体放入容量为m的背包的最大价值;
arr[i-1][m] : 前i-1个物体放入容量为m的背包的最大价值;
arr[i-1][m-w[i]] : 前i-1个物体放入容量为m-w[i]的背包的最大价值;
由此可得:
arr[i][m]=max{arr[i-1][m-w[i]]+p[i] , arr[i-1][m]}


public class BackPack {
    public static void main(String[] args) {
        int[] w = { 3, 4, 5 };//每个货物的重量
        int[] p = { 4, 5, 6 };//每个货物的价值(与上面对应)

        int m=10;               //背包最大承重
        int n=w.length;
        int[][] arr=new int[n+1][m+1];//定义二维数组存储每种情况下背包里的物品价值   

        int i,j;

        for(i=0;i<=n;i++){      //将前(i+1)个物品放入承重为0的包里价值为0
            arr[i][0]=0;
        }

        for(j=0;j<=m;j++){      //将前0个物品放入承重为j的包里价值为0
            arr[0][j]=0;
        }

        for(j=0;j<=m;j++){      //j表示背包承重(从0递增至m)
            for(i=1;i<=n;i++){  //i表示第i个货物
                if(j<w[i-1]){   //如果第i个货物的重量w[i-1]大于背包承重则舍弃这个货物
                    arr[i][j]=arr[i-1][j];
                }else{          //如果第i个货物的重量w[i-1]小于背包承重则取两者之间最大值
                    arr[i][j]=Math.max(arr[i-1][j-w[i-1]]+p[i-1],arr[i-1][j]);
                }//或许你会问为什么取最大,加入第i个肯定比不加大呀!你说的没错但是你必须考虑能不能加,至于能不能加交给它前面的去考虑,这也是动态规划的思想之一
            }
        }

        System.out.println(arr[n][m]);


    }

}

四、最长公共子序列
这里写图片描述


public class LCS {
    public static void main(String[] args) {
        String str1="ABCDABDC";
        String str2="BBCDCADBCAD";
        char[] ch1=str1.toCharArray();
        char[] ch2=str2.toCharArray();
        int m=ch1.length;
        int n=ch2.length;
        int[][] arr=new int[m+1][n+1];
        int i,j;
        for(i=0;i<=m;i++){
            arr[i][0]=0;
        }
        for(j=0;j<=n;j++){
            arr[0][j]=0;
        }
        for(i=1;i<=m;i++){
            for(j=1;j<=n;j++){
                if(ch1[i-1]==ch2[j-1]){
                    arr[i][j]=arr[i-1][j-1]+1;
                }else{
                    arr[i][j]=Math.max(arr[i-1][j], arr[i][j-1]);
                }
            }
        }
        System.out.println(arr[m][n]);      
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值