modify code

master
algorithmzuo 2 years ago
parent c0e9fe57f2
commit f488b8dbb6

@ -0,0 +1,57 @@
package 03.mca_09;
import java.util.LinkedList;
// 本题测试链接 : https://leetcode.com/problems/basic-calculator-iii/
public class Code01_ExpressionCompute {
public static int calculate(String str) {
return f(str.toCharArray(), 0)[0];
}
// 请从str[i...]往下算,遇到字符串终止位置或者右括号,就停止
// 返回两个值长度为2的数组
// 0) 负责的这一段的结果是多少
// 1) 负责的这一段计算到了哪个位置
public static int[] f(char[] str, int i) {
LinkedList<String> queue = new LinkedList<String>();
int cur = 0;
int[] bra = null;
// 从i出发开始撸串
while (i < str.length && str[i] != ')') {
if (str[i] >= '0' && str[i] <= '9') {
cur = cur * 10 + str[i++] - '0';
} else if (str[i] != '(') { // 遇到的是运算符号
addNum(queue, cur, str[i++]);
cur = 0;
} else { // 遇到左括号了
bra = f(str, i + 1);
cur = bra[0];
i = bra[1] + 1;
}
}
addNum(queue, cur, '+');
return new int[] { getAns(queue), i };
}
public static void addNum(LinkedList<String> queue, int num, char op) {
if (!queue.isEmpty() && (queue.peekLast().equals("*") || queue.peekLast().equals("/"))) {
String top = queue.pollLast();
int pre = Integer.valueOf(queue.pollLast());
num = top.equals("*") ? (pre * num) : (pre / num);
}
queue.addLast(String.valueOf(num));
queue.addLast(String.valueOf(op));
}
public static int getAns(LinkedList<String> queue) {
int ans = Integer.valueOf(queue.pollFirst());
while (queue.size() > 1) {
String op = queue.pollFirst();
int num = Integer.valueOf(queue.pollFirst());
ans += op.equals("+") ? num : -num;
}
return ans;
}
}

@ -0,0 +1,27 @@
package 03.mca_09;
// 本题测试链接 : https://leetcode.com/problems/longest-substring-without-repeating-characters/
public class Code02_LongestSubstringWithoutRepeatingCharacters {
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;
}
}

@ -0,0 +1,44 @@
package 03.mca_09;
// 测试链接 : https://leetcode.com/problems/minimum-window-substring/
public class Code03_MinWindowLength {
public static String minWindow(String s, String t) {
if (s.length() < t.length()) {
return "";
}
char[] str = s.toCharArray();
char[] target = t.toCharArray();
int[] map = new int[256];
for (char cha : target) {
map[cha]++;
}
int all = target.length;
int L = 0;
int R = 0;
int minLen = Integer.MAX_VALUE;
int ansl = -1;
int ansr = -1;
while (R != str.length) {
map[str[R]]--;
if (map[str[R]] >= 0) {
all--;
}
if (all == 0) {
while (map[str[L]] < 0) {
map[str[L++]]++;
}
if (minLen > R - L + 1) {
minLen = R - L + 1;
ansl = L;
ansr = R;
}
all++;
map[str[L++]]++;
}
R++;
}
return minLen == Integer.MAX_VALUE ? "" : s.substring(ansl, ansr + 1);
}
}

@ -0,0 +1,63 @@
package 03.mca_09;
public class Code04_Knapsack {
// 所有的货重量和价值都在w和v数组里
// 为了方便,其中没有负数
// bag背包容量不能超过这个载重
// 返回:不超重的情况下,能够得到的最大价值
public static int maxValue(int[] w, int[] v, int bag) {
if (w == null || v == null || w.length != v.length || w.length == 0) {
return 0;
}
// 尝试函数!
return process(w, v, 0, bag);
}
// index 0~N
// rest 负~bag
public static int process(int[] w, int[] v, int index, int rest) {
if (rest < 0) {
return -1;
}
if (index == w.length) {
return 0;
}
int p1 = process(w, v, index + 1, rest);
int p2 = 0;
int next = process(w, v, index + 1, rest - w[index]);
if (next != -1) {
p2 = v[index] + next;
}
return Math.max(p1, p2);
}
public static int dp(int[] w, int[] v, int bag) {
if (w == null || v == null || w.length != v.length || w.length == 0) {
return 0;
}
int N = w.length;
int[][] dp = new int[N + 1][bag + 1];
for (int index = N - 1; index >= 0; index--) {
for (int rest = 0; rest <= bag; rest++) {
int p1 = dp[index + 1][rest];
int p2 = 0;
int next = rest - w[index] < 0 ? -1 : dp[index + 1][rest - w[index]];
if (next != -1) {
p2 = v[index] + next;
}
dp[index][rest] = Math.max(p1, p2);
}
}
return dp[0][bag];
}
public static void main(String[] args) {
int[] weights = { 3, 2, 4, 7, 3, 1, 7 };
int[] values = { 5, 6, 3, 19, 12, 4, 2 };
int bag = 15;
System.out.println(maxValue(weights, values, bag));
System.out.println(dp(weights, values, bag));
}
}

@ -0,0 +1,24 @@
package 03.mca_09;
// 测试链接 : https://leetcode.cn/problems/coin-change-ii/
public class Code05_CoinChange {
public static int change(int aim, int[] arr) {
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 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];
}
}

@ -0,0 +1,124 @@
package 03.mca_09;
// 这个问题leetcode上可以直接测
// 链接https://leetcode.com/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];
}
}

@ -0,0 +1,135 @@
package 03.mca_09;
// 测试链接 : https://leetcode.com/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];
}
}
Loading…
Cancel
Save