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 }