常用算法解析-动态规划

 1 import java.util.HashMap;
 2 
 3 /**
 4  * 
 5  *原文链接: https://wx.abbao.cn/a/4736-4b66e5f9ec584ee0.html
 6  * 
 7  * 走楼梯问题:有一座高度是10级台阶的楼梯,从下往上走,每跨一步只能向上1级或者2级台阶。要求用程序来求出一共有多少种走法。
 8  * 
 9  * 這是一道入门级的动态递归问题
10  * 
11  * 问题分析:
12  * 
13  * 最有子结构: 最后一步走到第十层有多少种方法?2种:8-》10;9-》10 那么如果走到 8 有x种情况,走到9有y中情况 走到10可以看成x+y
14  * 
15  * 状态转移方程 若用公式表达f(10)=f(9)+f(8) 既 f(n) = f(n-1) + f(n-2)
16  * 
17  * 边界 走到第二层可以走一步,也可以走俩步。即f(2) = 2 第一层只能走一步 f(1) =1
18  * 
19  * 以上是问题建模 解析来是问题求解
20  */
21 public class WalkStair {
22     public static void main(String[] args) {
23         System.out.println(getWayStair1(10));
24         System.out.println(getWayStair2(10, new HashMap<Integer, Integer>()));
25         System.out.println(getWayStair3(10));
26     }
27 
28     /**
29      * 第一种思路:用递归的方式
30      * 
31      * @param n n层楼梯
32      * 
33      *          这里需要注意一下复杂度问题 这个二叉树长度n-1,节点2^n-1,时间复杂度2^n
34      */
35     public static int getWayStair1(int n) {
36         if (n == 1) {
37             return 1;
38         }
39         if (n == 2) {
40             return 2;
41         }
42         return getWayStair1(n - 1) + getWayStair1(n - 2);
43     }
44 
45     /**
46      * 第二种思路:还是递归,但是重复的计算几点可以不在计算,叫做备忘录算法 利用map将已经计算过的节点保存
47      * 
48      * 时间复杂度是 o(n)
49      * 
50      * @param n
51      * @param map
52      * @return
53      */
54     public static int getWayStair2(int n, HashMap<Integer, Integer> map) {
55         if (n == 1) {
56             return 1;
57         }
58         if (n == 2) {
59             return 2;
60         }
61         if (map.containsKey(n)) {
62             return map.get(n);
63         } else {
64             int value = getWayStair1(n - 1) + getWayStair1(n - 2);
65             map.put(n, value);
66             return value;
67         }
68     }
69 
70     /**
71      * 第三种思路:动态规划,每次得到的结果只是上俩次结果的和 时间复杂度o(n) 空间复杂度o(1)
72      * 
73      * @param n
74      * @return
75      */
76     public static int getWayStair3(int n) {
77         if (n == 0) {
78             return 0;
79         }
80         if (n == 1) {
81             return 1;
82         }
83         if (n == 2) {
84             return 2;
85         }
86 
87         int a = 1;
88         int b = 2;
89         int temp = 0;
90         for (int i = 3; i <= n; i++) {
91             temp = a + b;
92             a = b;
93             b = temp;
94         }
95         return temp;
96     }
97 }

 

 1 /**
 2  * 问题描述:十个人挖五座金矿,求挖到的最多的金子个数
 3  * 
 4  * 思路: 最优子结构: ‘1:第五座金矿挖 ’2:第五座金矿不挖 边界: ‘1:挖一座金矿 人数够 ’2:挖一座金矿人数不够 状态转移方程
 5  *
 6  */
 7 public class GoldMiner {
 8     /**
 9      * 
10      * @param n 前 n 座矿
11      * @param w 工人个数
12      * @param p 每座矿需要的工人个数
13      * @param g 每座矿的金子个数
14      * @return
15      */
16     public static int getMaxGold(int n, int w, int p[], int g[]) {
17 
18         // ‘前三个if是边界值
19         if (n < 1) {
20             return 0;
21         }
22         if (n == 1 && w < p[0]) {
23             return 0;
24         }
25         if (n == 1 && w >= p[0]) {
26             return g[0];
27         }
28 
29         // ’这里是初始化结果
30         int[] preResult = new int[w + 1];
31         int[] result = new int[w + 1];
32         for (int i = 0; i < w; i++) {
33             if (w >= p[0]) {
34                 preResult[i] = g[0];
35             } else {
36                 preResult[i] = 0;
37             }
38         }
39 
40         /**
41          * ‘外层循环控制挖第几座金矿,内层第一层循环控制可能挖的最优结果,内层第二层循环刷新可能获得最优结果,最後返回當前人人数能挖的最优结果
42          */
43         for (int i = 0; i < n; i++) {
44             for (int j = 0; j <= w; j++) {
45                 if (j < p[i]) {
46                     result[j] = preResult[j];
47                 } else {
48                     result[j] = Math.max(preResult[j], preResult[j - p[i]] + g[i]);
49                 }
50             }
51             for (int j = 0; j <= w; j++) {
52                 preResult[j] = result[j];
53             }
54         }
55         return result[w];
56     }
57 
58     public static void main(String[] args) {
59         int[] g = { 400, 500, 200, 300, 350 };
60         int[] p = { 5, 5, 3, 4, 3 };
61         System.out.println(getMaxGold(5, 10, p, g));
62     }
63 }

 

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 /**
 5  * 问题:
 6  * Given a non-empty string s and a dictionary wordDict containing a list of
 7  * non-empty words, determine if s can be segmented into a space-separated
 8  * sequence of one or more dictionary words.
 9  *
10  */
11 public class Lc139 {
12     /**
13      * 思路:dp 上一个串的位置到当前截取串的位置恰好是一个字典串
14      * @param s
15      * @param wordDict
16      * @return
17      */
18     public static boolean wordBreak(String s, List<String> wordDict) {
19         boolean[] dp = new boolean[s.length() + 1];
20         dp[0] = true;
21 
22         for (int i = 1; i < dp.length; i++) {
23             for (int j = 0; j < i; j++) {
24                 if (true == dp[j] && wordDict.contains(s.substring(j, i))) {
25                     dp[i] = true;
26                 }
27             }
28         }
29         return dp[s.length()];
30     }
31 
32     public static void main(String[] args) {
33         String s = "leetcode";
34         String s1 = "leet";
35         String s2 = "code";
36         List<String> wordDict = new ArrayList<String>();
37         wordDict.add(s1);
38         wordDict.add(s2);
39         System.out.println(wordBreak(s, wordDict));
40     }
41 }

 

posted @ 2019-11-18 10:16  小傻孩丶儿  阅读(275)  评论(0编辑  收藏  举报