美文网首页
算法(04)动态规划

算法(04)动态规划

作者: 迷心迷 | 来源:发表于2020-02-09 19:47 被阅读0次
    零钱问题
    public class CoinChange {
    
        public static void main(String[] args) {
            System.out.println(coins5(41, new int[] {1, 5, 25, 20}));
            // fib(40)
            
            // dp(i) 第i项斐波那契数
            // dp(i) = dp(i - 1) + dp(i - 2)
            
            // dp(41) = 凑够41需要的最少硬币数量 = min { dp(40), dp(36), dp(16), dp(21) } + 1
            // dp(41 - 1) = dp(40) = 凑够40需要的最少硬币数量
            // dp(41 - 5) = dp(36) = 凑够36需要的最少硬币数量
            // dp(41 - 25) = dp(16) = 凑够16需要的最少硬币数量
            // dp(41 - 20) = dp(21) = 凑够21需要的最少硬币数量
            // min { dp(40), dp(36), dp(16), dp(21) } + 1
        }
    
        static int coins5(int n, int[] faces) {
            if (n < 1 || faces == null || faces.length == 0) return -1;
            int[] dp = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                int min = Integer.MAX_VALUE;
                for (int face : faces) {
                    if (i < face) continue;
                    int v = dp[i - face];
                    if (v < 0 || v >= min) continue;
                    min = v;
                }
                if (min == Integer.MAX_VALUE) {
                    dp[i] = -1;
                } else {
                    dp[i] = min + 1;
                }
            }
            return dp[n];
        }
    
        static int coins4(int n) {
            if (n < 1) return -1;
            int[] dp = new int[n + 1];
            // faces[i]是凑够i分时最后那枚硬币的面值
            int[] faces = new int[dp.length];
            for (int i = 1; i <= n; i++) {
                int min = dp[i - 1];
                faces[i] = 1;
    
                if (i >= 5 && dp[i - 5] < min) {
                    min = dp[i - 5];
                    faces[i] = 5;
                }
                if (i >= 20 && dp[i - 20] < min) {
                    min = dp[i - 20];
                    faces[i] = 20;
                }
                if (i >= 25 && dp[i - 25] < min) {
                    min = dp[i - 25];
                    faces[i] = 25;
                }
                dp[i] = min + 1;
                print(faces, i);
            }
    //      print(faces, n);
            return dp[n];
        }
        
        static void print(int[] faces, int n) {
            System.out.print("[" + n + "] = ");
            while (n > 0) {
                System.out.print(faces[n] + " ");
                n -= faces[n];
            }
            System.out.println();
        }
        
        /**
         * 递推(自底向上)
         */
        static int coins3(int n) {
            if (n < 1) return -1;
            int[] dp = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                int min = dp[i - 1];
                if (i >= 5) min = Math.min(dp[i - 5], min);
                if (i >= 20) min = Math.min(dp[i - 20], min);
                if (i >= 25) min = Math.min(dp[i - 25], min);
                dp[i] = min + 1;
            }
            return dp[n];
        }
        
        /**
         * 记忆化搜索(自顶向下的调用)
         */
        static int coins2(int n) {
            if (n < 1) return -1;
            int[] dp = new int[n + 1];
            int[] faces = {1, 5, 20, 25};
            for (int face : faces) {
                if (n < face) break;
                dp[face] = 1;
            }
            return coins2(n, dp);
        }
        
        static int coins2(int n, int[] dp) {
            if (n < 1) return Integer.MAX_VALUE;
            if (dp[n] == 0) {
                int min1 = Math.min(coins2(n - 25, dp), coins2(n - 20, dp));
                int min2 = Math.min(coins2(n - 5, dp), coins2(n - 1, dp));
                dp[n] = Math.min(min1, min2) + 1;
            }
            return dp[n];
        }
        
        /**
         * 暴力递归(自顶向下的调用,出现了重叠子问题)
         */
        static int coins1(int n) {
            if (n < 1) return Integer.MAX_VALUE;
            if (n == 25 || n == 20 || n == 5 || n == 1) return 1;
            int min1 = Math.min(coins1(n - 25), coins1(n - 20));
            int min2 = Math.min(coins1(n - 5), coins1(n - 1));
            return Math.min(min1, min2) + 1;
        }
    }
    
    

    背包问题

    public class Knapsack {
        public static void main(String[] args) {
            int[] values = {6, 3, 5, 4, 6};
            int[] weights = {2, 2, 6, 5, 4};
            int capacity = 10;
            System.out.println(maxValueExactly(values, weights, capacity));
        }
        
        /**
         * @return 如果返回-1,代表没法刚好凑到capacity这个容量
         */
        static int maxValueExactly(int[] values, int[] weights, int capacity) {
            if (values == null || values.length == 0) return 0;
            if (weights == null || weights.length == 0) return 0;
            if (values.length != weights.length || capacity <= 0) return 0;
            int[] dp = new int[capacity + 1];
            for (int j = 1; j <= capacity; j++) {
                dp[j] = Integer.MIN_VALUE;
            }
            for (int i = 1; i <= values.length; i++) {
                for (int j = capacity; j >= weights[i - 1]; j--) {
                    dp[j] = Math.max(dp[j], values[i - 1] + dp[j - weights[i - 1]]);
                }
            }
            return dp[capacity] < 0 ? -1 : dp[capacity];
        }
        
        static int maxValue(int[] values, int[] weights, int capacity) {
            if (values == null || values.length == 0) return 0;
            if (weights == null || weights.length == 0) return 0;
            if (values.length != weights.length || capacity <= 0) return 0;
            int[] dp = new int[capacity + 1];
            for (int i = 1; i <= values.length; i++) {
                for (int j = capacity; j >= weights[i - 1]; j--) {
                    dp[j] = Math.max(dp[j], values[i - 1] + dp[j - weights[i - 1]]);
                }
            }
            return dp[capacity];
        }
        
        static int maxValue2(int[] values, int[] weights, int capacity) {
            if (values == null || values.length == 0) return 0;
            if (weights == null || weights.length == 0) return 0;
            if (values.length != weights.length || capacity <= 0) return 0;
            int[] dp = new int[capacity + 1];
            for (int i = 1; i <= values.length; i++) {
                for (int j = capacity; j >= 1; j--) {
                    if (j < weights[i - 1]) continue;
                    dp[j] = Math.max(dp[j], values[i - 1] + dp[j - weights[i - 1]]);
                }
            }
            return dp[capacity];
        }
        
        static int maxValue1(int[] values, int[] weights, int capacity) {
            if (values == null || values.length == 0) return 0;
            if (weights == null || weights.length == 0) return 0;
            if (values.length != weights.length || capacity <= 0) return 0;
            int[][] dp = new int[values.length + 1][capacity + 1];
            for (int i = 1; i <= values.length; i++) {
                for (int j = 1; j <= capacity; j++) {
                    if (j < weights[i - 1]) {
                        dp[i][j] = dp[i - 1][j];
                    } else {
                        dp[i][j] = Math.max(
                                dp[i - 1][j], 
                                values[i - 1] + dp[i - 1][j - weights[i - 1]]);
                    }
                }
            }
            return dp[values.length][capacity];
        }
    }
    
    

    最长公共子序列

    public class LCS {
        public static void main(String[] args) {
            int len = lcs(new int[] {1, 3, 5, 9, 10}, new int[] {1, 4, 9, 10});
            System.out.println(len);
        }
        
        public int longestCommonSubsequence(String text1, String text2) {
            if (text1 == null || text2 == null) return 0;
            char[] chars1 = text1.toCharArray();  
            if (chars1.length == 0) return 0;
            char[] chars2 = text2.toCharArray();  
            if (chars2.length == 0) return 0;
            char[] rowsChars = chars1, colsChars = chars2;
            if (chars1.length < chars2.length) {
                colsChars = chars1;
                rowsChars = chars2;
            }
            int[] dp = new int[colsChars.length + 1];
            for (int i = 1; i <= rowsChars.length; i++) {
                int cur = 0;
                for (int j = 1; j <= colsChars.length; j++) {
                    int leftTop = cur;
                    cur = dp[j];
                    if (rowsChars[i - 1] == colsChars[j - 1]) {
                        dp[j] = leftTop + 1;
                    } else {
                        dp[j] = Math.max(dp[j], dp[j - 1]);
                    }
                }
            }
            return dp[colsChars.length];
        }
        
        static int lcs(int[] nums1, int[] nums2) {
            if (nums1 == null || nums1.length == 0) return 0;
            if (nums2 == null || nums2.length == 0) return 0;
            int[] rowsNums = nums1, colsNums = nums2;
            if (nums1.length < nums2.length) {
                colsNums = nums1;
                rowsNums = nums2;
            }
            int[] dp = new int[colsNums.length + 1];
            for (int i = 1; i <= rowsNums.length; i++) {
                int cur = 0;
                for (int j = 1; j <= colsNums.length; j++) {
                    int leftTop = cur;
                    cur = dp[j];
                    if (rowsNums[i - 1] == colsNums[j - 1]) {
                        dp[j] = leftTop + 1;
                    } else {
                        dp[j] = Math.max(dp[j], dp[j - 1]);
                    }
                }
            }
            return dp[colsNums.length];
        }
        
        static int lcs4(int[] nums1, int[] nums2) {
            if (nums1 == null || nums1.length == 0) return 0;
            if (nums2 == null || nums2.length == 0) return 0;
            int[] dp = new int[nums2.length + 1];
            for (int i = 1; i <= nums1.length; i++) {
                int cur = 0;
                for (int j = 1; j <= nums2.length; j++) {
                    int leftTop = cur;
                    cur = dp[j];
                    if (nums1[i - 1] == nums2[j - 1]) {
                        dp[j] = leftTop + 1;
                    } else {
                        dp[j] = Math.max(dp[j], dp[j - 1]);
                    }
                }
            }
            return dp[nums2.length];
        }
        
        static int lcs3(int[] nums1, int[] nums2) {
            if (nums1 == null || nums1.length == 0) return 0;
            if (nums2 == null || nums2.length == 0) return 0;
            int[][] dp = new int[2][nums2.length + 1];
            for (int i = 1; i <= nums1.length; i++) {
                int row = i & 1;
                int prevRow = (i - 1) & 1;
                for (int j = 1; j <= nums2.length; j++) {
                    if (nums1[i - 1] == nums2[j - 1]) {
                        dp[row][j] = dp[prevRow][j - 1] + 1;
                    } else {
                        dp[row][j] = Math.max(dp[prevRow][j], dp[row][j - 1]);
                    }
                }
            }
            return dp[nums1.length & 1][nums2.length];
        }
        
        static int lcs2(int[] nums1, int[] nums2) {
            if (nums1 == null || nums1.length == 0) return 0;
            if (nums2 == null || nums2.length == 0) return 0;
            int[][] dp = new int[nums1.length + 1][nums2.length + 1];
            for (int i = 1; i <= nums1.length; i++) {
                for (int j = 1; j <= nums2.length; j++) {
                    if (nums1[i - 1] == nums2[j - 1]) {
                        dp[i][j] = dp[i - 1][j - 1] + 1;
                    } else {
                        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                    }
                }
            }
            return dp[nums1.length][nums2.length];
        }
        
        static int lcs1(int[] nums1, int[] nums2) {
            if (nums1 == null || nums1.length == 0) return 0;
            if (nums2 == null || nums2.length == 0) return 0;
            return lcs1(nums1, nums1.length, nums2, nums2.length);
        }
        
        /**
         * 求nums1前i个元素和nums2前j个元素的最长公共子序列长度
         * @param nums1
         * @param i
         * @param nums2
         * @param j
         */
        static int lcs1(int[] nums1, int i, int[] nums2, int j) {
            if (i == 0 || j == 0) return 0;
            if (nums1[i - 1] == nums2[j - 1]) {
                return lcs1(nums1, i - 1, nums2, j - 1) + 1;
            }
            return Math.max(lcs1(nums1, i - 1, nums2, j), 
                            lcs1(nums1, i, nums2, j - 1));
        }
    }
    
    

    最长公共子串

    public class LCSubstring {
    
        public static void main(String[] args) {
            System.out.println(lcs("ABDCBA", "ABBA"));
        }
        
        static int lcs(String str1, String str2) {
            if (str1 == null || str2 == null) return 0;
            char[] chars1 = str1.toCharArray();
            if (chars1.length == 0) return 0;
            char[] chars2 = str2.toCharArray();
            if (chars2.length == 0) return 0;
            char[] rowsChars = chars1, colsChars = chars2;
            if (chars1.length < chars2.length) {
                colsChars = chars1;
                rowsChars = chars2;
            }
            
            int[] dp = new int[colsChars.length + 1];
            int max = 0;
            for (int row = 1; row <= rowsChars.length; row++) {
                for (int col = colsChars.length; col >= 1; col--) {
                    if (chars1[row - 1] != chars2[col - 1]) {
                        dp[col] = 0;
                    } else {
                        dp[col] = dp[col - 1] + 1;
                        max = Math.max(dp[col], max);
                    }
                }
            }
            return max;
        }
        
        static int lcs2(String str1, String str2) {
            if (str1 == null || str2 == null) return 0;
            char[] chars1 = str1.toCharArray();
            if (chars1.length == 0) return 0;
            char[] chars2 = str2.toCharArray();
            if (chars2.length == 0) return 0;
            char[] rowsChars = chars1, colsChars = chars2;
            if (chars1.length < chars2.length) {
                colsChars = chars1;
                rowsChars = chars2;
            }
            
            int[] dp = new int[colsChars.length + 1];
            int max = 0;
            for (int row = 1; row <= rowsChars.length; row++) {
                int cur = 0;
                for (int col = 1; col <= colsChars.length; col++) {
                    int leftTop = cur;
                    cur = dp[col];
                    if (chars1[row - 1] != chars2[col - 1]) {
                        dp[col] = 0;
                    } else {
                        dp[col] = leftTop + 1;
                        max = Math.max(dp[col], max);
                    }
                }
            }
            return max;
        }
        
        static int lcs1(String str1, String str2) {
            if (str1 == null || str2 == null) return 0;
            char[] chars1 = str1.toCharArray();
            if (chars1.length == 0) return 0;
            char[] chars2 = str2.toCharArray();
            if (chars2.length == 0) return 0;
            int[][] dp = new int[chars1.length + 1][chars2.length + 1];
            int max = 0;
            for (int i = 1; i <= chars1.length; i++) {
                for (int j = 1; j <= chars2.length; j++) {
                    if (chars1[i - 1] != chars2[j - 1]) continue;
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    max = Math.max(dp[i][j], max);
                }
            }
            return max;
        }
    
    }
    
    

    最长上升子序列

    public class LIS {
        public static void main(String[] args) {
            System.out.println(lengthOfLIS(new int[] {10, 2, 2, 5, 1, 7, 101, 18}));
        }
    
        /**
         * 牌顶
         */
        static int lengthOfLIS(int[] nums) {
            if (nums == null || nums.length == 0) return 0;
            // 牌堆的数量
            int len = 0;
            // 牌顶数组
            int[] top = new int[nums.length];
            // 遍历所有的牌
            for (int num : nums) {
                int begin = 0;
                int end = len;
                while (begin < end) {
                    int mid = (begin + end) >> 1;
                    if (num <= top[mid]) {
                        end = mid;
                    } else {
                        begin = mid + 1;
                    }
                }
                // 覆盖牌顶
                top[begin] = num;
                // 检查是否要新建一个牌堆
                if (begin == len) len++;
            }
            return len;
        }
    
        /**
         * 牌顶
         */
        static int lengthOfLIS2(int[] nums) {
            if (nums == null || nums.length == 0) return 0;
            // 牌堆的数量
            int len = 0;
            // 牌顶数组
            int[] top = new int[nums.length];
            // 遍历所有的牌
            for (int num : nums) {
                int j = 0;
                while (j < len) {
                    // 找到一个>=num的牌顶
                    if (top[j] >= num) {
                        top[j] = num;
                        break;
                    }
                    // 牌顶 < num
                    j++;
                }
                if (j == len) { // 新建一个牌堆
                    len++;
                    top[j] = num;
                }
            }
            return len;
        }
    
        /**
         * 动态规划
         */
        static int lengthOfLIS1(int[] nums) {
            if (nums == null || nums.length == 0) return 0;
            int[] dp = new int[nums.length];
            int max = dp[0] = 1;
            for (int i = 1; i < dp.length; i++) {
                dp[i] = 1;
                for (int j = 0; j < i; j++) {
                    if (nums[i] <= nums[j]) continue;
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
                max = Math.max(dp[i], max);
            }
            return max;
        }
    
    }
    
    

    最大连续子序列和

    public class MaxSubArray {
        public static void main(String[] args) {
            System.out.println(maxSubArray2(new int[] {-2,1,-3,4,-1,2,1,-5,4}));
        }
        
        static int maxSubArray2(int[] nums) {
            if (nums == null || nums.length == 0) return 0;
            int dp = nums[0];
            int max = dp;
            for (int i = 1; i < nums.length; i++) {
                if (dp <= 0) {
                    dp = nums[i];
                } else {
                    dp = dp + nums[i];
                }
                max = Math.max(dp, max);
            }
            return max;
        }
        
        static int maxSubArray1(int[] nums) {
            if (nums == null || nums.length == 0) return 0;
            int[] dp = new int[nums.length];
            dp[0] = nums[0];
            int max = dp[0];
            for (int i = 1; i < dp.length; i++) {
                int prev = dp[i - 1];
                if (prev <= 0) {
                    dp[i] = nums[i];
                } else {
                    dp[i] = prev + nums[i];
                }
                max = Math.max(dp[i], max);
            }
            return max;
        }
    }
    
    

    相关文章

      网友评论

          本文标题:算法(04)动态规划

          本文链接:https://www.haomeiwen.com/subject/rytauctx.html