modify code

master
algorithmzuo 1 year ago
parent 3997009620
commit b975d71de0

@ -10,6 +10,7 @@ import java.util.LinkedList;
// 本题测试链接 : https://leetcode.cn/problems/basic-calculator-iii/
public class Code01_ExpressionCompute {
// "7 + 3 0 * ( 7 + 2 ) + ...."
public static int calculate(String str) {
return f(str.toCharArray(), 0)[0];
}

@ -1,28 +1,54 @@
package 03.mca_09;
import java.util.Arrays;
// 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
// 测试链接 : https://leetcode.cn/problems/longest-substring-without-repeating-characters/
public class Code02_LongestSubstringWithoutRepeatingCharacters {
public static int lengthOfLongestSubstring(String s) {
if (s == null || s.equals("")) {
public static int lengthOfLongestSubstring(String str) {
if (str == null || str.length() == 0) {
return 0;
}
char[] str = s.toCharArray();
int[] map = new int[256];
for (int i = 0; i < 256; i++) {
map[i] = -1;
}
map[str[0]] = 0;
int N = str.length;
// 长度 >= 1
char[] s = str.toCharArray();
int n = s.length;
int[] preIndex = new int[256];
Arrays.fill(preIndex, -1);
int ans = 1;
int pre = 1;
for (int i = 1; i < N; i++) {
pre = Math.min(i - map[str[i]], pre + 1);
ans = Math.max(ans, pre);
map[str[i]] = i;
int preAns = 1;
preIndex[s[0]] = 0;
for (int i = 1; i < n; i++) {
int preApear = preIndex[s[i]];
int p1 = i - preApear;
int p2 = preAns + 1;
int curAns = Math.min(p1, p2);
ans = Math.max(ans, curAns);
preIndex[s[i]] = i;
preAns = curAns;
}
return ans;
}
// public static int lengthOfLongestSubstring(String s) {
// if (s == null || s.equals("")) {
// return 0;
// }
// char[] str = s.toCharArray();
// int[] map = new int[256];
// for (int i = 0; i < 256; i++) {
// map[i] = -1;
// }
// map[str[0]] = 0;
// int N = str.length;
// int ans = 1;
// int pre = 1;
// for (int i = 1; i < N; i++) {
// pre = Math.min(i - map[str[i]], pre + 1);
// ans = Math.max(ans, pre);
// map[str[i]] = i;
// }
// return ans;
// }
}

@ -1,91 +0,0 @@
package 03.mca_09;
// 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额
// 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0
// 假设每一种面额的硬币有无限个
// 题目数据保证结果符合 32 位带符号整数
// 测试链接 : https://leetcode.cn/problems/coin-change-ii/
public class Code05_CoinChange {
public static int change1(int aim, int[] arr) {
return process1(arr, 0, aim);
}
public static int process1(int[] arr, int i, int j) {
if (j < 0) {
return 0;
}
if (i == arr.length) {
return j == 0 ? 1 : 0;
}
return process1(arr, i + 1, j) + process1(arr, i, j - arr[i]);
}
public static int change2(int aim, int[] arr) {
int n = arr.length;
int[][] dp = new int[n][aim + 1];
for (int i = 0; i < n; i++) {
for (int j = 0; j <= aim; j++) {
dp[i][j] = -1;
}
}
return process2(arr, 0, aim, dp);
}
public static int process2(int[] arr, int i, int j, int[][] dp) {
if (j < 0) {
return 0;
}
if (i == arr.length) {
return j == 0 ? 1 : 0;
}
if (dp[i][j] != -1) {
return dp[i][j];
}
int ans = process2(arr, i + 1, j, dp) + process2(arr, i, j - arr[i], dp);
dp[i][j] = ans;
return ans;
}
public static int change3(int aim, int[] arr) {
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 j = 0; j <= aim; j++) {
dp[i][j] = dp[i + 1][j];
if (j - arr[i] >= 0) {
dp[i][j] += dp[i][j - arr[i]];
}
}
}
return dp[0][aim];
}
public static int change4(int aim, int[] arr) {
int n = arr.length;
int[] dp = new int[aim + 1];
dp[0] = 1;
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j <= aim; j++) {
if (j - arr[i] >= 0) {
dp[j] += dp[j - arr[i]];
}
}
}
return dp[aim];
}
public static int change5(int aim, int[] arr) {
int n = arr.length;
int[] dp = new int[aim + 1];
dp[0] = 1;
for (int i = n - 1; i >= 0; i--) {
for (int j = arr[i]; j <= aim; j++) {
dp[j] += dp[j - arr[i]];
}
}
return dp[aim];
}
}

@ -1,131 +0,0 @@
package 03.mca_09;
// 给定两个字符串 text1 和 text2返回这两个字符串的最长 公共子序列 的长度
// 如果不存在 公共子序列 ,返回 0
// 一个字符串的 子序列 是指这样一个新的字符串:
// 它是由原字符串在不改变字符的相对顺序的情况下
// 删除某些字符(也可以不删除任何字符)后组成的新字符串
// 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列
// 两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列
// 这个问题leetcode上可以直接测
// 链接https://leetcode.cn/problems/longest-common-subsequence/
public class Code06_LongestCommonSubsequence {
public static int longestCommonSubsequence1(String s1, String s2) {
if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
return 0;
}
char[] str1 = s1.toCharArray();
char[] str2 = s2.toCharArray();
// 尝试
return process1(str1, str2, str1.length - 1, str2.length - 1);
}
// str1[0...i]和str2[0...j],这个范围上最长公共子序列长度是多少?
// 可能性分类:
// a) 最长公共子序列一定不以str1[i]字符结尾、也一定不以str2[j]字符结尾
// b) 最长公共子序列可能以str1[i]字符结尾、但是一定不以str2[j]字符结尾
// c) 最长公共子序列一定不以str1[i]字符结尾、但是可能以str2[j]字符结尾
// d) 最长公共子序列必须以str1[i]字符结尾、也必须以str2[j]字符结尾
// 注意a)、b)、c)、d)并不是完全互斥的,他们可能会有重叠的情况
// 但是可以肯定,答案不会超过这四种可能性的范围
// 那么我们分别来看一下,这几种可能性怎么调用后续的递归。
// a) 最长公共子序列一定不以str1[i]字符结尾、也一定不以str2[j]字符结尾
// 如果是这种情况那么有没有str1[i]和str2[j]就根本不重要了,因为这两个字符一定没用啊
// 所以砍掉这两个字符,最长公共子序列 = str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归)
// b) 最长公共子序列可能以str1[i]字符结尾、但是一定不以str2[j]字符结尾
// 如果是这种情况那么我们可以确定str2[j]一定没有用要砍掉但是str1[i]可能有用,所以要保留
// 所以,最长公共子序列 = str1[0...i]与str2[0...j-1]的最长公共子序列长度(后续递归)
// c) 最长公共子序列一定不以str1[i]字符结尾、但是可能以str2[j]字符结尾
// 跟上面分析过程类似,最长公共子序列 = str1[0...i-1]与str2[0...j]的最长公共子序列长度(后续递归)
// d) 最长公共子序列必须以str1[i]字符结尾、也必须以str2[j]字符结尾
// 同时可以看到可能性d)存在的条件一定是在str1[i] == str2[j]的情况下,才成立的
// 所以,最长公共子序列总长度 = str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归) + 1(共同的结尾)
// 综上,四种情况已经穷尽了所有可能性。四种情况中取最大即可
// 其中b)、c)一定参与最大值的比较,
// 当str1[i] == str2[j]时a)一定比d)小所以d)参与
// 当str1[i] != str2[j]时d)压根不存在所以a)参与
// 但是再次注意了!
// a)是str1[0...i-1]与str2[0...j-1]的最长公共子序列长度
// b)是str1[0...i]与str2[0...j-1]的最长公共子序列长度
// c)是str1[0...i-1]与str2[0...j]的最长公共子序列长度
// a)中str1的范围 < b)中str1的范围a)中str2的范围 == b)中str2的范围
// 所以a)不用求也知道它比不过b)啊因为有一个样本的范围比b)小啊!
// a)中str1的范围 == c)中str1的范围a)中str2的范围 < c)中str2的范围
// 所以a)不用求也知道它比不过c)啊因为有一个样本的范围比c)小啊!
// 至此可以知道a)就是个垃圾,有它没它,都不影响最大值的决策
// 所以当str1[i] == str2[j]时b)、c)、d)中选出最大值
// 当str1[i] != str2[j]时b)、c)中选出最大值
public static int process1(char[] str1, char[] str2, int i, int j) {
if (i == 0 && j == 0) {
// str1[0..0]和str2[0..0],都只剩一个字符了
// 那如果字符相等公共子序列长度就是1不相等就是0
// 这显而易见
return str1[i] == str2[j] ? 1 : 0;
} else if (i == 0) {
// 这里的情况为:
// str1[0...0]和str2[0...j]str1只剩1个字符了但是str2不只一个字符
// 因为str1只剩一个字符了所以str1[0...0]和str2[0...j]公共子序列最多长度为1
// 如果str1[0] == str2[j]那么此时相等已经找到了公共子序列长度就是1也不可能更大了
// 如果str1[0] != str2[j],只是此时不相等而已,
// 那么str2[0...j-1]上有没有字符等于str1[0]呢?不知道,所以递归继续找
if (str1[i] == str2[j]) {
return 1;
} else {
return process1(str1, str2, i, j - 1);
}
} else if (j == 0) {
// 和上面的else if同理
// str1[0...i]和str2[0...0]str2只剩1个字符了但是str1不只一个字符
// 因为str2只剩一个字符了所以str1[0...i]和str2[0...0]公共子序列最多长度为1
// 如果str1[i] == str2[0]那么此时相等已经找到了公共子序列长度就是1也不可能更大了
// 如果str1[i] != str2[0],只是此时不相等而已,
// 那么str1[0...i-1]上有没有字符等于str2[0]呢?不知道,所以递归继续找
if (str1[i] == str2[j]) {
return 1;
} else {
return process1(str1, str2, i - 1, j);
}
} else { // i != 0 && j != 0
// 这里的情况为:
// str1[0...i]和str2[0...i]str1和str2都不只一个字符
// 看函数开始之前的注释部分
// p1就是可能性c)
int p1 = process1(str1, str2, i - 1, j);
// p2就是可能性b)
int p2 = process1(str1, str2, i, j - 1);
// p3就是可能性d)如果可能性d)存在即str1[i] == str2[j]那么p3就求出来参与pk
// 如果可能性d)不存在即str1[i] != str2[j]那么让p3等于0然后去参与pk反正不影响
int p3 = str1[i] == str2[j] ? (1 + process1(str1, str2, i - 1, j - 1)) : 0;
return Math.max(p1, Math.max(p2, p3));
}
}
public static int longestCommonSubsequence2(String s1, String s2) {
if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
return 0;
}
char[] str1 = s1.toCharArray();
char[] str2 = s2.toCharArray();
int N = str1.length;
int M = str2.length;
int[][] dp = new int[N][M];
dp[0][0] = str1[0] == str2[0] ? 1 : 0;
for (int j = 1; j < M; j++) {
dp[0][j] = str1[0] == str2[j] ? 1 : dp[0][j - 1];
}
for (int i = 1; i < N; i++) {
dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0];
}
for (int i = 1; i < N; i++) {
for (int j = 1; j < M; j++) {
int p1 = dp[i - 1][j];
int p2 = dp[i][j - 1];
int p3 = str1[i] == str2[j] ? (1 + dp[i - 1][j - 1]) : 0;
dp[i][j] = Math.max(p1, Math.max(p2, p3));
}
}
return dp[N - 1][M - 1];
}
}

@ -1,140 +0,0 @@
package 03.mca_09;
// 给你一个字符串 s 和一个字符规律 p
// 请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
// '.' 匹配任意单个字符
// '*' 匹配零个或多个前面的那一个元素
// 所谓匹配,是要涵盖 整个 字符串 s的而不是部分字符串。
// 测试链接 : https://leetcode.cn/problems/regular-expression-matching/
public class Code07_RegularExpressionMatch {
public static boolean isValid(char[] s, char[] e) {
// s中不能有'.' or '*'
for (int i = 0; i < s.length; i++) {
if (s[i] == '*' || s[i] == '.') {
return false;
}
}
// 开头的e[0]不能是'*',没有相邻的'*'
for (int i = 0; i < e.length; i++) {
if (e[i] == '*' && (i == 0 || e[i - 1] == '*')) {
return false;
}
}
return true;
}
// 初始尝试版本,不包含斜率优化
public static boolean isMatch1(String str, String exp) {
if (str == null || exp == null) {
return false;
}
char[] s = str.toCharArray();
char[] e = exp.toCharArray();
return isValid(s, e) && process(s, e, 0, 0);
}
// str[si.....] 能不能被 exp[ei.....]配出来! true false
public static boolean process(char[] s, char[] e, int si, int ei) {
if (ei == e.length) { // exp 没了 str
return si == s.length;
}
// exp[ei]还有字符
// ei + 1位置的字符不是*
if (ei + 1 == e.length || e[ei + 1] != '*') {
// ei + 1 不是*
// str[si] 必须和 exp[ei] 能配上!
return si != s.length && (e[ei] == s[si] || e[ei] == '.') && process(s, e, si + 1, ei + 1);
}
// exp[ei]还有字符
// ei + 1位置的字符是*!
while (si != s.length && (e[ei] == s[si] || e[ei] == '.')) {
if (process(s, e, si, ei + 2)) {
return true;
}
si++;
}
return process(s, e, si, ei + 2);
}
// 改记忆化搜索+斜率优化
public static boolean isMatch2(String str, String exp) {
if (str == null || exp == null) {
return false;
}
char[] s = str.toCharArray();
char[] e = exp.toCharArray();
if (!isValid(s, e)) {
return false;
}
int[][] dp = new int[s.length + 1][e.length + 1];
// dp[i][j] = 0, 没算过!
// dp[i][j] = -1 算过返回值是false
// dp[i][j] = 1 算过返回值是true
return isValid(s, e) && process2(s, e, 0, 0, dp);
}
public static boolean process2(char[] s, char[] e, int si, int ei, int[][] dp) {
if (dp[si][ei] != 0) {
return dp[si][ei] == 1;
}
boolean ans = false;
if (ei == e.length) {
ans = si == s.length;
} else {
if (ei + 1 == e.length || e[ei + 1] != '*') {
ans = si != s.length && (e[ei] == s[si] || e[ei] == '.') && process2(s, e, si + 1, ei + 1, dp);
} else {
if (si == s.length) { // ei ei+1 *
ans = process2(s, e, si, ei + 2, dp);
} else { // si没结束
if (s[si] != e[ei] && e[ei] != '.') {
ans = process2(s, e, si, ei + 2, dp);
} else { // s[si] 可以和 e[ei]配上
ans = process2(s, e, si, ei + 2, dp) || process2(s, e, si + 1, ei, dp);
}
}
}
}
dp[si][ei] = ans ? 1 : -1;
return ans;
}
// 动态规划版本 + 斜率优化
public static boolean isMatch3(String str, String pattern) {
if (str == null || pattern == null) {
return false;
}
char[] s = str.toCharArray();
char[] p = pattern.toCharArray();
if (!isValid(s, p)) {
return false;
}
int N = s.length;
int M = p.length;
boolean[][] dp = new boolean[N + 1][M + 1];
dp[N][M] = true;
for (int j = M - 1; j >= 0; j--) {
dp[N][j] = (j + 1 < M && p[j + 1] == '*') && dp[N][j + 2];
}
// dp[0..N-2][M-1]都等于false只有dp[N-1][M-1]需要讨论
if (N > 0 && M > 0) {
dp[N - 1][M - 1] = (s[N - 1] == p[M - 1] || p[M - 1] == '.');
}
for (int i = N - 1; i >= 0; i--) {
for (int j = M - 2; j >= 0; j--) {
if (p[j + 1] != '*') {
dp[i][j] = ((s[i] == p[j]) || (p[j] == '.')) && dp[i + 1][j + 1];
} else {
if ((s[i] == p[j] || p[j] == '.') && dp[i + 1][j]) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i][j + 2];
}
}
}
}
return dp[0][0];
}
}

@ -0,0 +1,154 @@
package 03.mca_09;
public class Test {
public static int f(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 1;
}
// n > 2
return f(n - 1) + f(n - 2);
}
public static int f2(int n) {
int[] dp = new int[n + 1];
return p2(n, dp);
}
public static int p2(int i, int[] dp) {
if (i == 1) {
return 1;
}
if (i == 2) {
return 1;
}
// i > 2
if (dp[i] != 0) {
return dp[i];
}
int ans = p2(i - 1, dp) + p2(i - 2, dp);
dp[i] = ans;
return ans;
}
public static void main(String[] args) {
int n = 7;
// 1 1 2 3 5 8 13
System.out.println("菲数列第 " + n + " 项,为" + f(n));
}
// 彻底暴力
public static int knapsack1(int[] w, int[] v, int bag) {
// 0...... bag
// 返回最大价值
return process(w, v, 0, bag);
}
// i....... 货自由选择背包的剩余载重是j
// 返回最大价值
public static int process(int[] w, int[] v, int i, int j) {
if (j < 0) {
// 剩余载重是负数!???
// 说明之前的选择有错,返回-1表示无效
return -1;
}
// j >= 0;
if (i == w.length) {
// 没货了!
return 0;
}
// 背包j >= 0
// 有货!
// 可能性1不要当前的货
int p1 = process(w, v, i + 1, j);
// 可能性2要当前的货
int p2 = 0;
int next2 = process(w, v, i + 1, j - w[i]);
if (next2 != -1) {
p2 = next2 + v[i];
}
return Math.max(p1, p2);
}
// 记忆化搜索
// 货物数量n <= 1000
// 背包容量bag <= 1000
public static int knapsack2(int[] w, int[] v, int bag) {
int n = w.length;
int[][] dp = new int[n][bag + 1];
for (int i = 0; i < n; i++) {
for (int j = 0; j <= bag; j++) {
dp[i][j] = -2;
}
}
return process2(w, v, 0, bag, dp);
}
// i....... 货自由选择背包的剩余载重是j
// 返回最大价值
public static int process2(int[] w, int[] v, int i, int j, int[][] dp) {
if (j < 0) {
return -1;
}
if (i == w.length) {
return 0;
}
if (dp[i][j] != -2) {
return dp[i][j];
}
int p1 = process2(w, v, i + 1, j, dp);
int p2 = 0;
int next2 = process2(w, v, i + 1, j - w[i], dp);
if (next2 != -1) {
p2 = next2 + v[i];
}
int ans = Math.max(p1, p2);
dp[i][j] = ans;
return ans;
}
public static int knapsack3(int[] w, int[] v, int bag) {
int n = w.length;
int[][] dp = new int[n + 1][bag + 1];
// dp[n][...] = 0
for (int i = n - 1; i >= 0; i--) {
// 每个格子依赖下一行的,两个位置的值
for (int j = 0; j <= bag; j++) {
// dp[i][j]
int p1 = dp[i + 1][j];
int p2 = 0;
if (j - w[i] >= 0) {
p2 = v[i] + dp[i + 1][j - w[i]];
}
dp[i][j] = Math.max(p1, p2);
}
}
return dp[0][bag];
}
public static int knapsack4(int[] w, int[] v, int bag) {
int n = w.length;
int[] dp = new int[bag + 1];
// 脑中[n][...] = 0
for (int i = n - 1; i >= 0; i--) {
// 每个格子依赖下一行的,两个位置的值
for (int j = bag; j >= 0; j--) {
// 0 1 2 3 4 5 6
// <-
int p1 = dp[j];
int p2 = 0;
if (j - w[i] >= 0) {
p2 = v[i] + dp[j - w[i]];
}
dp[j] = Math.max(p1, p2);
}
}
// 第0行的值
return dp[bag];
}
}
Loading…
Cancel
Save