zoukankan      html  css  js  c++  java
  • java数据结构03

    1.动态规划

    如果使用上面的递归函数进行计算,会导致如下的重复计算:

    示例:

    1.1实战示例1

    从一个列表中选出一堆(若干)不相邻的数字,使这些数字相加的和最大。

    package datastruct.t05dynamic_programming;
    
    public class DynamicProgramming {
        /**
         * 递归方式
         * 
         * @param arr:数组
         * @param i:第i个位置
         * @return
         */
        public static int recOpt(int[] arr, int i) {
            if (i == 0)
                return arr[0];
            if (i == 1)
                return Math.max(arr[0], arr[1]);
            else {
                int A = recOpt(arr, i - 2) + arr[i];
                int B = recOpt(arr, i - 1);
                return Math.max(A, B);
            }
        }
    
        /**
         * 非递归的方式
         */
        public static int dpOpt(int[] arr) {
            int[] opt = new int[arr.length];
            opt[0] = arr[0];
            opt[1] = Math.max(arr[0], arr[1]);
            for (int i = 2; i < arr.length; i++) {
                int A = opt[i - 2] + arr[i];
                int B = opt[i - 1];
                opt[i] = Math.max(A, B);
            }
            return opt[arr.length - 1];
        }
    
        public static void main(String[] args) {
            int[] arr = { 1, 2, 4, 1, 7, 8, 3 };
            int res = recOpt(arr, arr.length - 1);
            System.out.println(res);
            int res2 = dpOpt(arr);
            System.out.println(res2);
        }
    
    }

    1.2实战示例2

    从某一数组里找出两个数字的和正好等于给定的数字,如果存在返回true,不存在返回false。

    package datastruct.t05dynamic_programming;
    
    public class Subset {
        /**
         * 递归的方式实现
         */
        public static boolean recSubset(int[] arr, int i, int target) {
            if (target == 0) {
                return true;
            } else if (i == 0) {
                return arr[0] == target;
            } else if (arr[i] > target) {
                return recSubset(arr, i - 1, target);
            } else {
                boolean A = recSubset(arr, i - 1, target - arr[i]);
                boolean B = recSubset(arr, i - 1, target);
                return A || B;
            }
        }
    
        public static void main(String[] args) {
            int[] arr = { 3, 34, 4, 12, 5, 2 };
            int target1 = 9;
            int target2 = 10;
            int target3 = 13;
            boolean res1 = recSubset(arr, arr.length - 1, target1);
            boolean res2 = recSubset(arr, arr.length - 1, target2);
            boolean res3 = recSubset(arr, arr.length - 1, target3);
            System.out.println(res1);
            System.out.println(res2);
            System.out.println(res3);
        }
    
    }

    package datastruct.t05dynamic_programming;
    
    public class Subset {
    
        /**
         * 非递归方式实现
         */
        public static boolean dpSubset(int[] arr, int target) {
            boolean[][] subset = new boolean[arr.length][target + 1];
            // 所有行,第0列
            for (int i = 0; i < subset.length; i++) {
                subset[i][0] = true;
            }
            // 第0行,所有列
            for (int j = 0; j < subset[0].length; j++) {
                subset[0][j] = false;
            }
            subset[0][arr[0]] = true;
            
            for (int i = 1; i < subset.length; i++) {
                for (int s = 1; s < subset[0].length; s++) {
                    if (arr[i] > s) {
                        subset[i][s] = subset[i - 1][s];
                    } else {
                        boolean A = subset[i - 1][s - arr[i]];
                        boolean B = subset[i - 1][s];
                        subset[i][s] = A || B;
                    }
                }
            }
            return subset[subset.length-1][subset[0].length-1];
        }
    
        public static void main(String[] args) {
            int[] arr = { 3, 34, 4, 12, 5, 2 };
            int target1 = 9;
            int target2 = 10;
            int target3 = 13;
        
            boolean res4 = dpSubset(arr, target1);
            boolean res5 = dpSubset(arr, target2);
            boolean res6 = dpSubset(arr, target3);
            System.out.println(res4);
            System.out.println(res5);
            System.out.println(res6);
        }
    
    }

    1.3DP01背包

    package datastruct.t05dynamic_programming;
    
    import java.util.Scanner;
    
    public class T01package {
    
        public static void main(String[] args) {
            //    int[] w = { 2, 3, 4, 5 };
            //    int[] v = { 3, 4, 5, 8 };
            Scanner input = new Scanner(System.in);
            String str1 = input.nextLine();
            String[] temp = str1.split(" ");//以空格拆分字符串
            int[] w = new int[temp.length];//int类型数组
            for (int i = 0; i < temp.length; i++) {
                w[i] = Integer.parseInt(temp[i]);//整数数组
            }
    
            String str2 = input.nextLine();
            String[] temp2 = str2.split(" ");
            int[] v = new int[temp.length];//int类型数组
            for (int i = 0; i < temp.length; i++) {
                v[i] = Integer.parseInt(temp2[i]);//整数数组
            }
    
            int[] w1 = new int[w.length + 1]; // 在原数组前面加个0,从而和原来的第几个物品对应起来
            System.arraycopy(w, 0, w1, 1, w.length);
            int[] v1 = new int[v.length + 1];
            System.arraycopy(v, 0, v1, 1, v.length);
    
            //    System.out.println(Arrays.toString(w1));
            //    System.out.println(Arrays.toString(v1));
    
            int res = fun(4, 8, w1, v1);
            System.out.println(res);
            
            int wNum = 5, vMax = 9;
            int[][] opt = new int[wNum][vMax];
            nfun(w1, v1, opt, wNum, vMax);
            for (int i = 0; i < opt.length; i++) {
                for (int j = 0; j < opt[0].length; j++) {
                    System.out.print(opt[i][j] + "	");
                }
                System.out.println();
            }
        }
    
        /**
         * 递归的方式实现
         * @param k:当前可以偷取的第k个物品
         * @param wk:当前背包的容量
         * @return
         */
        public static int fun(int k, int wk, int[] w, int[] v) {
            if (k == 0 || wk == 0)
                return 0;
            else if (wk < w[k]) {
                return fun(k - 1, wk, w, v);
            } else {
                int A = fun(k - 1, wk, w, v);
                int B = fun(k - 1, wk - w[k], w, v) + v[k];
                return Math.max(A, B);
            }
        }
    
        /**
         * 非递归实现
         */
        public static void nfun(int[] w, int[] v, int[][] opt, int wNum, int vMax) {
            for (int i = 1; i < wNum; i++) {
                for (int j = 1; j < vMax; j++) {
                    if (j < w[i]) { // 当前的剩余容量比物品的容量小
                        opt[i][j] = opt[i - 1][j];
                    } else {
                        opt[i][j] = Math.max(opt[i - 1][j], opt[i - 1][j - w[i]] + v[i]);
                    }
                }
            }
        }
    
    }

    1.4最长递增子序列

    给定一个长度为N的数组,找出一个最长的单调递增子序列,子序列不一定连续,但初始顺序不能乱。

    例如:给定一个长度为6的数组A{4, 5, 7, 1,3, 9},则其最长的单调递增子序列为{4,5,7,9},长度为4。

    该问题满足最优子结构性质,因此可以使用动态规划求解。

    定义如下符号:

    • n表示问题序列的总长度。
    • A[1:i]表示下标从1到i的一个序列,特别地,A[1:n]表示下标从1开始,长度为n的一个序列,也就是问题的输入。
    • A_i表示A[1:n]中的第i个元素。

    由于问题的最优解必然对应某个子序列,而这个子序列又必然由某个A_i结尾,因此,由所有A_i结尾的最长递增序列的长度,构成了问题的解空间。因此,再引入符号L,来描述问题的解空间:

    • L_i表示以A_i结尾的最长递增子序列的长度。

    显然,A_i为该递增子序列的最大值,max (L_i)就是问题的最优解。

    求解max (L_i),就要得到所有的L_i。求解L_i这一问题,包含了求解从L_{1}L_{i-1}的所有子问题,从而满足最优子结构性质。

    递归方程如下:

    L_k=egin{cases} 1, & {forall} iin [1,k), A_kleqslant A_i\ max(L_i)+1|iin [1,k), A_k> A_i , & exists iin [1,k), A_k> A_i end{cases}

    转换成代码,思路就是遍历所有A_i,选择满足A_k>A_i的最大的L_i,则L_k=L_i+1,如果A_k比所有A_i都要小,则L_k=1

    package nowcode2;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Scanner;
    
    public class T24MaxLengthOfSubsequence {
    
        public static void main(String[] args) {
            Scanner input = new Scanner(System.in);
            while (input.hasNext()) {
                String str = input.nextLine();
                String[] arr = str.split(" ");
                int[] nums = new int[arr.length];
                for (int i = 0; i < nums.length; i++) {
                    nums[i] = Integer.parseInt(arr[i]);
                }
                int res = getMaxLengthOfSubsequence(nums);
                System.out.println(res);
            }
            input.close();
        }
    
        //获得最长子序列
        public static int getMaxLengthOfSubsequence(int[] nums) {
            int n = nums.length;
            int[] ls = new int[n];
            int res = 1;
    for (int i = 0; i < n; i++) {//填充ls int maxValue = 1; ls[i] = 1; for (int j = 0; j < i; j++) { ///遍历所有的A if (nums[i] > nums[j]) { maxValue = max(maxValue, ls[j] + 1); } ls[i] = maxValue; } } int index = 0; //最长子序列末尾出现的位置 for (int i = 0; i < n; i++) { //查找最大的子序列 if (ls[i] > res) { res = ls[i]; index = i; } } int count = res; //从后往前找子序列 int[] arrRes = new int[count]; arrRes[--count] = nums[index]; for (int i = index; i >= 0; i--) { if (nums[i] < nums[index] && ls[i] == ls[index] - 1) { arrRes[--count] = nums[i]; index = i; } } System.out.println(Arrays.toString(arrRes)); return res; } public static int max(int a, int b) { return a > b ? a : b; } }

  • 相关阅读:
    Mac上TexStudio无法显示中文字符的问题
    python中import与from方法总结
    Jupter Notebook 使用技法
    python把列表(list)传给函数形参时的问题剖析
    Spyder常用快捷键
    用Tinkercad学arduino之 多喇叭发声
    用Tinkercad学arduino之 播放旋律
    用Tinkercad学arduino之 音调键盘 按键改变音调
    用Tinkercad学arduino之 伺服电机摆动
    用Tinkercad学arduino之 读取电位器模拟输入
  • 原文地址:https://www.cnblogs.com/xinmomoyan/p/12238008.html
Copyright © 2011-2022 走看看