You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
6.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_06_4_week;
import java.util.Arrays;
import java.util.HashMap;
import java.util.TreeSet;
// 给定字符串 S and T找出 S 中最短的(连续)子串 W ,使得 T 是 W 的 子序列 。
// 如果 S 中没有窗口可以包含 T 中的所有字符,返回空字符串 ""。
// 如果有不止一个最短长度的窗口,返回开始位置最靠左的那个。
// 示例 1
// 输入:
// S = "abcdebdde", T = "bde"
// 输出:"bcde"
// 解释:
// "bcde" 是答案,因为它在相同长度的字符串 "bdde" 出现之前。
// "deb" 不是一个更短的答案,因为在窗口中必须按顺序出现 T 中的元素。
// 测试链接 : https://leetcode.cn/problems/minimum-window-subsequence/
public class Code01_MinimumWindowSubsequence {
// public static int minLenContainsT1(char[] s, char[] t) {
// int n = s.length;
// int m = t.length;
//
// // s = xya...a...
// // t = abc
// int min = Integer.MAX_VALUE;
// for (int i = 0; i < n; i++) {
// if(s[i] == t[0]) {
// int findEnd = findEnd(s, t, i);
// if(findEnd != -1) { // 找到了s[i...findEnd]答案
// min = Math.min(min, findEnd - i + 1);
// }
// }
// }
// return min;
// }
//
// // s = a.....?
// // si
// // t = abcd
// // 0
// // 最后的s[si...?] 整出来t的整体
// // 如果从si出发就没有t的整体返回-1
// public static int findEnd(char[] s, char[] t, int si) {
//
// }
public static void main(String[] args) {
String s = "xxaxxbxxcxx";
// 0 8
String t = "abc";
System.out.println(minLen(s, t));
}
public static int minLen(String str, String target) {
char[] s = str.toCharArray();
char[] t = target.toCharArray();
int len = Integer.MAX_VALUE;
for (int i = 0; i < s.length; i++) {
// 0 > t
// 1 > t
// 2 > t
int end = zuo(s, t, i, 0);
if (end != Integer.MAX_VALUE) {
int cur = end - i;
len = Math.min(len, cur);
}
}
return len;
}
// s[si.....]
// t[ti....]
// 把t的整体都配出来s在哪能尽早结束的下个位置
// s = x x a x x b x x c x a b c
// 0 1 2 3 4 5 6 7 8 9 10 11 12
// t = a b c
// 0 1 2
// s[1...] t[0...]
// s[4...] t[1...] 8
// s[4...] t[0...] 12
public static int zuo(char[] s, char[] t, int si, int ti) {
if (ti == t.length) { // 配完了!
return si;
}
// ti < t.length;
if (si == s.length) {
return Integer.MAX_VALUE;
}
// 都有字符
// 可能性1根本不让s[si]去消化掉t[ti]
int p1 = zuo(s, t, si + 1, ti);
// 可能性2让s[si]去消化掉t[ti]
int p2 = Integer.MAX_VALUE;
if (s[si] == t[ti]) {
// si ti
p2 = zuo(s, t, si + 1, ti + 1);
}
return Math.min(p1, p2);
}
public String minWindow1(String s, String t) {
char[] str = s.toCharArray();
char[] target = t.toCharArray();
int n = str.length;
// key : 字符! value:有序表!
HashMap<Character, TreeSet<Integer>> map = new HashMap<>();
for (char cha : target) {
map.put(cha, new TreeSet<>());
}
for (int i = 0; i < n; i++) {
if (map.containsKey(str[i])) {
map.get(str[i]).add(i);
}
}
int ansLen = Integer.MAX_VALUE;
int l = -1;
int r = -1;
for (int i = 0; i < n; i++) {
if (str[i] == target[0]) {
int right = right1(str, i, target, map);
if (right != -1 && (right - i) < ansLen) {
ansLen = right - i;
l = i;
r = right;
}
}
}
return l == -1 ? "" : s.substring(l, r);
}
public static int right1(char[] str, int si, char[] target, HashMap<Character, TreeSet<Integer>> map) {
int ti = 0;
while (ti != target.length) {
if (si == str.length) {
return -1;
}
if (str[si] == target[ti]) {
si++;
ti++;
} else {
Integer next = map.get(target[ti]).ceiling(si);
if (next == null) {
return -1;
} else {
si = next;
}
}
}
return si;
}
public String minWindow2(String s, String t) {
char[] str = s.toCharArray();
char[] target = t.toCharArray();
int n = str.length;
int[] last = new int[26];
int[][] near = new int[n][26];
for (int i = 0; i < n; i++) {
Arrays.fill(near[i], -1);
}
for (int i = 0; i < n; i++) {
int cha = str[i] - 'a';
for (int j = last[cha]; j < i; j++) {
near[j][cha] = i;
}
last[cha] = i;
}
int ansLen = Integer.MAX_VALUE;
int l = -1;
int r = -1;
for (int i = 0; i < n; i++) {
if (str[i] == target[0]) {
int right = right2(str, i, target, near);
if (right != -1 && (right - i) < ansLen) {
ansLen = right - i;
l = i;
r = right;
}
}
}
return l == -1 ? "" : s.substring(l, r);
}
public static int right2(char[] str, int si, char[] target, int[][] near) {
int ti = 0;
while (ti != target.length) {
if (si == str.length) {
return -1;
}
if (str[si] == target[ti]) {
si++;
ti++;
} else {
si = near[si][target[ti] - 'a'];
}
if (si == -1) {
return -1;
}
}
return si;
}
public String minWindow3(String s, String t) {
char[] str = s.toCharArray();
char[] target = t.toCharArray();
int len = Integer.MAX_VALUE;
int l = -1;
int r = -1;
for (int si = 0; si < str.length; si++) {
int right = process(str, target, si, 0);
if (right != Integer.MAX_VALUE && right - si < len) {
len = right - si;
l = si;
r = right;
}
}
return l == -1 ? "" : s.substring(l, r);
}
public static int process(char[] str, char[] target, int si, int ti) {
if (ti == target.length) {
return si;
}
if (si == str.length) {
return Integer.MAX_VALUE;
}
int r1 = process(str, target, si + 1, ti);
int r2 = str[si] == target[ti] ? process(str, target, si + 1, ti + 1) : Integer.MAX_VALUE;
return Math.min(r1, r2);
}
public String minWindow4(String s, String t) {
char[] str = s.toCharArray();
char[] target = t.toCharArray();
int n = str.length;
int m = target.length;
int[][] dp = new int[n + 1][m + 1];
for (int si = 0; si <= n; si++) {
dp[si][m] = si;
}
for (int ti = 0; ti < m; ti++) {
dp[n][ti] = Integer.MAX_VALUE;
}
for (int si = n - 1; si >= 0; si--) {
for (int ti = m - 1; ti >= 0; ti--) {
int r1 = dp[si + 1][ti];
int r2 = str[si] == target[ti] ? dp[si + 1][ti + 1] : Integer.MAX_VALUE;
dp[si][ti] = Math.min(r1, r2);
}
}
int len = Integer.MAX_VALUE;
int l = -1;
int r = -1;
for (int si = 0; si < str.length; si++) {
int right = dp[si][0];
if (right != Integer.MAX_VALUE && right - si < len) {
len = dp[si][0] - si;
l = si;
r = right;
}
}
return l == -1 ? "" : s.substring(l, r);
}
}