package class_2023_02_4_week; import java.util.ArrayList; import java.util.Arrays; // 你想要用小写字母组成一个目标字符串 target。 // 开始的时候,序列由 target.length 个 '?' 记号组成 // 而你有一个小写字母印章 stamp。 // 在每个回合,你可以将印章放在序列上,并将序列中的每个字母替换为印章上的相应字母 // 你最多可以进行 10 * target.length 个回合 // 举个例子,如果初始序列为 "?????",而你的印章 stamp 是 "abc" // 那么在第一回合,你可以得到 "abc??"、"?abc?"、"??abc" //(请注意,印章必须完全包含在序列的边界内才能盖下去。) // 如果可以印出序列,那么返回一个数组,该数组由每个回合中被印下的最左边字母的索引组成 // 如果不能印出序列,就返回一个空数组。 // 例如,如果序列是 "ababc",印章是 "abc" // 那么我们就可以返回与操作 "?????" -> "abc??" -> "ababc" 相对应的答案 [0, 2] // 另外,如果可以印出序列,那么需要保证可以在 10 * target.length 个回合内完成 // 任何超过此数字的答案将不被接受 // 测试链接 : https://leetcode.cn/problems/stamping-the-sequence/ public class Code04_StampingTheSequence { public static int[] movesToStamp(String stamp, String target) { char[] s = stamp.toCharArray(); char[] t = target.toCharArray(); int m = s.length; int n = t.length; int[] inDegrees = new int[n - m + 1]; // 所有在target里开头的字符串,认为和stamp,每个位置都不一样 Arrays.fill(inDegrees, m); ArrayList> graph = new ArrayList<>(); for (int i = 0; i < n; i++) { graph.add(new ArrayList<>()); } // 入度为0的开头,进入到queue里 int[] queue = new int[n - m + 1]; int l = 0; int r = 0; for (int i = 0; i <= n - m; i++) { // i....撸m个字符 for (int j = 0; j < m; j++) { if (t[i + j] == s[j]) { if (--inDegrees[i] == 0) { queue[r++] = i; } } else { graph.get(i + j).add(i); } } } // visited[17] == true boolean[] visited = new boolean[n]; int[] path = new int[n - m + 1]; int size = 0; while (l < r) { // cur位置开头的字符串,弹出了!入度为0!恭喜啊!!!! int cur = queue[l++]; path[size++] = cur; for (int i = 0; i < m; i++) { if (!visited[cur + i]) { visited[cur + i] = true; for (int next : graph.get(cur + i)) { if (--inDegrees[next] == 0) { queue[r++] = next; } } } } } if (size != n - m + 1) { return new int[0]; } // path里 for (int i = 0, j = size - 1; i < j; i++, j--) { int tmp = path[i]; path[i] = path[j]; path[j] = tmp; } return path; } }