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 }