update on 2020-5-17

pull/3/head
algorithmzuo 5 years ago
parent 5817dce9cf
commit 582ca375f6

@ -16,32 +16,55 @@ public class Code06_ConvertToLetterString {
if (i == str.length) { // base case
return 1;
}
// i没有到终止位置
if (str[i] == '0') {
return 0;
}
// i没有到终止位置
// str[i]字符不是0
if (str[i] == '1') {
int res = process(str, i + 1); // i自己作为单独的部分后续有多少种方法
int res = process(str, i + 1);
if (i + 1 < str.length) {
res += process(str, i + 2); // (i和i+1)作为单独的部分,后续有多少种方法
res += process(str, i + 2);
}
return res;
}
if (str[i] == '2') {
int res = process(str, i + 1); // i自己作为单独的部分后续有多少种方法
// (i和i+1)作为单独的部分并且没有超过26后续有多少种方法
int res = process(str, i + 1);
if (i + 1 < str.length && (str[i + 1] >= '0' && str[i + 1] <= '6')) {
res += process(str, i + 2); // (i和i+1)作为单独的部分,后续有多少种方法
}
return res;
}
// str[i] == '3' ~ '9'
return process(str, i + 1);
}
public static int dpWays2(String s) {
if (s == null || s.length() == 0) {
return 0;
}
char[] str = s.toCharArray();
int N = str.length;
int[] dp = new int[N+1];
dp[N] = 1;
for(int i = N-1; i >= 0; i--) {
if (str[i] == '0') {
dp[i] = 0;
}
if (str[i] == '1') {
dp[i] = dp[i + 1];
if (i + 1 < str.length) {
dp[i] += dp[i + 2];
}
}
if (str[i] == '2') {
dp[i] = dp[i + 1];
if (i + 1 < str.length && (str[i + 1] >= '0' && str[i + 1] <= '6')) {
dp[i] += dp[i + 2]; // (i和i+1)作为单独的部分,后续有多少种方法
}
}
}
return dp[0];
}
public static int dpWays(String s) {
if (s == null || s.length() == 0) {
return 0;
@ -72,6 +95,7 @@ public class Code06_ConvertToLetterString {
public static void main(String[] args) {
System.out.println(number("11111"));
System.out.println(dpWays2("11111"));
}
}

@ -12,6 +12,9 @@ public class Code08_CardsInLine {
);
}
// L....R
// F S L+1..R
// L..R-1
public static int f(int[] arr, int L, int R) {
if (L == R) {
return arr[L];
@ -23,14 +26,14 @@ public class Code08_CardsInLine {
);
}
// i..j
public static int s(int[] arr, int i, int j) {
if (i == j) {
// arr[L..R]
public static int s(int[] arr, int L, int R) {
if (L == R) {
return 0;
}
return Math.min(
f(arr, i + 1, j), // arr[i]
f(arr, i, j - 1) // arr[j]
f(arr, L + 1, R), // arr[i]
f(arr, L, R - 1) // arr[j]
);
}
@ -38,24 +41,41 @@ public class Code08_CardsInLine {
if (arr == null || arr.length == 0) {
return 0;
}
int[][] f = new int[arr.length][arr.length];
int[][] s = new int[arr.length][arr.length];
for (int j = 0; j < arr.length; j++) {
f[j][j] = arr[j];
for (int i = j - 1; i >= 0; i--) {
f[i][j] = Math.max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);
s[i][j] = Math.min(f[i + 1][j], f[i][j - 1]);
int N = arr.length;
int[][] f = new int[N][N];
int[][] s = new int[N][N];
for(int i = 0; i < N;i++) {
f[i][i] = arr[i];
}
// s[i][i] = 0;
for(int i = 1; i < N;i++) {
int L =0;
int R =i;
while(L < N && R < N) {
f[L][R] = Math.max(
arr[L] + s[L + 1][ R],
arr[R] + s[L][R - 1]
);
s[L][R] = Math.min(
f[L + 1][R], // arr[i]
f[L][R - 1] // arr[j]
);
L++;
R++;
}
}
return Math.max(f[0][arr.length - 1], s[0][arr.length - 1]);
return Math.max(f[0][N-1], s[0][N-1]);
}
public static void main(String[] args) {
int[] arr = { 4,7,9,5 };
int[] arr = { 4,7,9,5,19,29,80,4 };
// A 4 9
// B 7 5
System.out.println(f(arr,0,3));
System.out.println(s(arr,0,3));
System.out.println(win1(arr));
System.out.println(win2(arr));
}

@ -6,15 +6,17 @@ import java.util.HashMap;
public class Code02_StickersToSpellWord {
public static int minStickers1(String[] stickers, String target) {
int n = stickers.length;
int[][] map = new int[n][26];
HashMap<String, Integer> dp = new HashMap<>();
int[][] map = new int[n][26];// stickers -> [26] [26] [26]
for (int i = 0; i < n; i++) {
char[] str = stickers[i].toCharArray();
for (char c : str) {
map[i][c - 'a']++;
}
}
HashMap<String, Integer> dp = new HashMap<>();
dp.put("", 0);
return process1(dp, map, target);
}
@ -22,37 +24,46 @@ public class Code02_StickersToSpellWord {
// dp 傻缓存如果t已经算过了直接返回dp中的值
// t 剩余的目标
// 0..N每一个字符串所含字符的词频统计
public static int process1(HashMap<String, Integer> dp, int[][] map, String t) {
if (dp.containsKey(t)) {
return dp.get(t);
// 返回值是-1map 中的贴纸 怎么都无法rest
public static int process1(
HashMap<String, Integer> dp,
int[][] map,
String rest) {
if (dp.containsKey(rest)) {
return dp.get(rest);
}
int ans = Integer.MAX_VALUE;
int n = map.length;
int[] tmap = new int[26];
char[] target = t.toCharArray();
// 以下就是正式的递归调用过程
int ans = Integer.MAX_VALUE; // ans -> 搞定rest使用的最少的贴纸数量
int n = map.length; // N种贴纸
int[] tmap = new int[26]; // tmap 去替代 rest
char[] target = rest.toCharArray();
for (char c : target) {
tmap[c - 'a']++;
}
for (int i = 0; i < n; i++) {
// 枚举当前第一张贴纸是谁?
if (map[i][target[0] - 'a'] == 0) {
continue;
}
StringBuilder sb = new StringBuilder();
for (int j = 0; j < 26; j++) {
// i 贴纸, j 枚举a~z字符
for (int j = 0; j < 26; j++) { //
if (tmap[j] > 0) { // j这个字符是target需要的
for (int k = 0; k < Math.max(0, tmap[j] - map[i][j]); k++) {
sb.append((char) ('a' + j));
}
}
}
// sb -> i
String s = sb.toString();
int tmp = process1(dp, map, s);
if (tmp != -1) {
ans = Math.min(ans, 1 + tmp);
}
}
dp.put(t, ans == Integer.MAX_VALUE ? -1 : ans);
return dp.get(t);
// ans 系统最大 rest
dp.put(rest, ans == Integer.MAX_VALUE ? -1 : ans);
return dp.get(rest);
}
public static int minStickers2(String[] stickers, String target) {
@ -129,4 +140,13 @@ public class Code02_StickersToSpellWord {
return ans;
}
public static void main(String[] args) {
String[] arr = {"aaaa","bbaa","ccddd"};
String str = "abcccccdddddbbbaaaaa";
System.out.println(minStickers1(arr, str));
System.out.println(minStickers2(arr, str));
}
}

@ -53,12 +53,15 @@ public class Code03_Knapsack {
public static int dpWay(int[] w, int[] v, int bag) {
int N = w.length;
int[][] dp = new int[N + 1][bag + 1];
// dp[N][...] = 0
for (int index = N - 1; index >= 0; index--) {
for (int rest = 1; rest <= bag; rest++) {
dp[index][rest] = dp[index + 1][rest];
if (rest >= w[index]) {
dp[index][rest] = Math.max(dp[index][rest], v[index] + dp[index + 1][rest - w[index]]);
for (int rest = 0; rest <= bag; rest++) { // rest < 0
int p1 = dp[index+1][rest];
int p2 = -1;
if(rest - w[index] >= 0) {
p2 = v[index] + dp[index + 1][rest - w[index]];
}
dp[index][rest] = Math.max(p1, p2);
}
}
return dp[0][bag];

@ -3,8 +3,17 @@ package class12;
public class Code05_PalindromeSubsequence {
public static int lcse(char[] str1, char[] str2) {
int[][] dp = new int[str1.length][str2.length];
dp[0][0] = str1[0] == str2[0] ? 1 : 0;
for (int i = 1; i < str1.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], str1[i] == str2[0] ? 1 : 0);
}

@ -93,20 +93,60 @@ public class Code06_Coffee {
}
// 方法二,洗咖啡杯的方式和原来一样,只是这个暴力版本减少了一个可变参数
// process(drinks, 3, 10, 0,0)
// a 洗一杯的时间 固定变量
// b 自己挥发干净的时间 固定变量
// drinks 每一个员工喝完的时间 固定变量
// drinks[0..index-1]都已经干净了,不用你操心了
// drinks[index...]都想变干净这是我操心的washLine表示洗的机器何时可用
// drinks[index...]变干净,最少的时间点返回
public static int process(int[] drinks, int a, int b, int index, int washLine) {
if (index == drinks.length - 1) {
return Math.min(Math.max(washLine, drinks[index]) + a, drinks[index] + b);
}
// 剩不止一杯咖啡
// wash是我当前的咖啡杯洗完的时间
int wash = Math.max(washLine, drinks[index]) + a;
int wash = Math.max(washLine, drinks[index]) + a;// 洗index一杯结束的时间点
// index+1...变干净的最早时间
int next1 = process(drinks, a, b, index + 1, wash);
// index....
int p1 = Math.max(wash, next1);
int dry = drinks[index] + b;
int dry = drinks[index] + b; // 挥发index一杯结束的时间点
int next2 = process(drinks, a, b, index + 1, washLine);
int p2 = Math.max(dry, next2);
return Math.min(p1, p2);
}
public static int dp(int[] drinks, int a, int b) {
if (a >= b) {
return drinks[drinks.length - 1] + b;
}
// a < b
int N = drinks.length;
int limit = 0; // 咖啡机什么时候可用
for (int i = 0; i < N; i++) {
limit = Math.max(limit, drinks[i]) + a;
}
int[][] dp = new int[N][limit + 1];
// N-1行所有的值
for (int washLine = 0; washLine <= limit; washLine++) {
dp[N - 1][washLine] = Math.min(Math.max(washLine, drinks[N - 1]) + a, drinks[N - 1] + b);
}
for(int index = N - 2; index >=0;index--) {
for(int washLine = 0; washLine <= limit; washLine++) {
int p1 = Integer.MAX_VALUE;
int wash = Math.max(washLine, drinks[index]) + a;
if(wash <= limit) {
p1 = Math.max(wash, dp[index+1][wash]);
}
int p2 = Math.max(drinks[index] + b, dp[index + 1][washLine]);
dp[index][washLine] = Math.min(p1, p2);
}
}
return dp[0][0];
}
// 方法三:最终版本,把方法二洗咖啡杯的暴力尝试进一步优化成动态规划
public static int minTime3(int[] arr, int n, int a, int b) {
PriorityQueue<Machine> heap = new PriorityQueue<Machine>(new MachineComparator());
@ -156,27 +196,40 @@ public class Code06_Coffee {
}
public static void main(String[] args) {
int[] arr = {1,1,5,5,7,10,12,12,12,12,12,12,15};
int a = 3;
int b = 10;
System.out.println(process(arr, a, b, 0, 0));
System.out.println(dp(arr, a, b));
int len = 5;
int max = 9;
int testTime = 50000;
for (int i = 0; i < testTime; i++) {
int[] arr = randomArray(len, max);
int n = (int) (Math.random() * 5) + 1;
int a = (int) (Math.random() * 5) + 1;
int b = (int) (Math.random() * 10) + 1;
int ans1 = minTime1(arr, n, a, b);
int ans2 = minTime2(arr, n, a, b);
int ans3 = minTime3(arr, n, a, b);
if (ans1 != ans2 || ans2 != ans3) {
printArray(arr);
System.out.println("n : " + n);
System.out.println("a : " + a);
System.out.println("b : " + b);
System.out.println(ans1 + " , " + ans2 + " , " + ans3);
System.out.println("===============");
break;
}
}
// for (int i = 0; i < testTime; i++) {
// int[] arr = randomArray(len, max);
// int n = (int) (Math.random() * 5) + 1;
// int a = (int) (Math.random() * 5) + 1;
// int b = (int) (Math.random() * 10) + 1;
// int ans1 = minTime1(arr, n, a, b);
// int ans2 = minTime2(arr, n, a, b);
// int ans3 = minTime3(arr, n, a, b);
// if (ans1 != ans2 || ans2 != ans3) {
// printArray(arr);
// System.out.println("n : " + n);
// System.out.println("a : " + a);
// System.out.println("b : " + b);
// System.out.println(ans1 + " , " + ans2 + " , " + ans3);
// System.out.println("===============");
// break;
// }
// }
}

@ -1,52 +1,108 @@
package class12;
import java.util.HashMap;
public class Code09_CoinsWay {
// arr中都是正数且无重复值返回组成aim的方法数
public static int ways(int[] arr, int aim) {
public static int ways1(int[] arr, int aim) {
if (arr == null || arr.length == 0 || aim < 0) {
return 0;
}
return process(arr, 0, aim);
return process1(arr, 0, aim);
}
// 如果自由使用arr[index...]的面值组成rest这么多钱返回方法数 1 , 6
public static int process(int[] arr, int index, int rest) {
if (index == arr.length) { // 无面值的时候
return rest == 0 ? 1 : 0;
public static int process1(int[] arr, int index, int rest) {
if(index == arr.length) {
return rest == 0 ? 1 : 0 ;
}
// 有面值的时候
int ways = 0;
// arr[index] 当钱面值
for (int zhang = 0; zhang * arr[index] <= rest; zhang++) {
ways += process(arr, index + 1, rest - zhang * arr[index]);
for(int zhang = 0; zhang * arr[index] <= rest ;zhang++) {
ways += process1(arr, index + 1, rest - (zhang * arr[index]) );
}
return ways;
}
public static int waysdp(int[] arr, int aim) {
public static int ways2(int[] arr, int aim) {
if (arr == null || arr.length == 0 || aim < 0) {
return 0;
}
int[][] dp = new int[arr.length+1][aim+1];
// 一开始所有的过程,都没有计算呢
// dp[..][..] = -1
for(int i = 0 ; i < dp.length; i++) {
for(int j = 0 ; j < dp[0].length; j++) {
dp[i][j] = -1;
}
}
return process2(arr, 0, aim , dp);
}
// 如果index和rest的参数组合是没算过的dp[index][rest] == -1
// 如果index和rest的参数组合是算过的dp[index][rest] > - 1
public static int process2(int[] arr,
int index, int rest,
int[][] dp) {
if(dp[index][rest] != -1) {
return dp[index][rest];
}
if(index == arr.length) {
dp[index][rest] = rest == 0 ? 1 :0;
return dp[index][rest];
}
int ways = 0;
for(int zhang = 0; zhang * arr[index] <= rest ;zhang++) {
ways += process2(arr, index + 1, rest - (zhang * arr[index]) , dp );
}
dp[index][rest] = ways;
return ways;
}
public static int ways3(int[] arr, int aim) {
if (arr == null || arr.length == 0 || aim < 0) {
return 0;
}
int N = arr.length;
int[][] dp = new int[N + 1][aim + 1];
dp[N][0] = 1;
for (int i = N - 1; i >= 0; i--) { // 大顺序 从下往上
for (int rest = 0; rest <= aim; rest++) {
dp[i][rest] = dp[i + 1][rest];
if (rest - arr[i] >= 0) {
dp[i][rest] += dp[i][rest - arr[i]];
dp[N][0] = 1;// dp[N][1...aim] = 0;
for(int index = N - 1; index >= 0; index--) {
for(int rest = 0; rest <= aim; rest++) {
int ways = 0;
for(int zhang = 0; zhang * arr[index] <= rest ;zhang++) {
ways += dp[index + 1] [rest - (zhang * arr[index])];
}
dp[index][rest] = ways;
}
}
return dp[0][aim];
}
public static int ways4(int[] arr, int aim) {
if (arr == null || arr.length == 0 || aim < 0) {
return 0;
}
int N = arr.length;
int[][] dp = new int[N + 1][aim + 1];
dp[N][0] = 1;// dp[N][1...aim] = 0;
for(int index = N - 1; index >= 0; index--) {
for(int rest = 0; rest <= aim; rest++) {
dp[index][rest] = dp[index+1][rest];
if(rest - arr[index] >= 0) {
dp[index][rest] += dp[index][rest - arr[index]];
}
}
}
return dp[0][aim];
}
public static void main(String[] args) {
int[] arr = { 5, 2, 3, 1 };
int sum = 350;
System.out.println(ways(arr, sum));
System.out.println(waysdp(arr, sum));
int[] arr = { 5, 10,50,100 };
int sum = 1000;
System.out.println(ways1(arr, sum));
System.out.println(ways2(arr, sum));
System.out.println(ways3(arr, sum));
System.out.println(ways4(arr, sum));
}
}

Loading…
Cancel
Save