戳印序列
难度:
标签:
题目描述
代码结果
运行时间: 51 ms, 内存: 16.4 MB
/*
* 使用Java Stream的题解
* 1. 与Java的解法类似,但是使用Stream来简化一些操作。
*/
import java.util.*;
import java.util.stream.*;
public class SolutionStream {
public int[] movesToStamp(String stamp, String target) {
char[] s = stamp.toCharArray();
char[] t = target.toCharArray();
int slen = s.length, tlen = t.length;
List<Integer> result = new ArrayList<>();
boolean[] visited = new boolean[tlen];
int stars = 0;
while (stars < tlen) {
boolean doneReplace = false;
for (int i = 0; i <= tlen - slen; i++) {
if (!visited[i] && canReplace(t, i, s)) {
stars = doReplace(t, i, slen, stars);
doneReplace = true;
visited[i] = true;
result.add(i);
if (stars == tlen) {
break;
}
}
}
if (!doneReplace) {
return new int[0];
}
}
Collections.reverse(result);
return result.stream().mapToInt(i -> i).toArray();
}
private boolean canReplace(char[] t, int p, char[] s) {
return IntStream.range(0, s.length).allMatch(i -> t[p + i] == '*' || t[p + i] == s[i]);
}
private int doReplace(char[] t, int p, int len, int stars) {
stars += (int) IntStream.range(0, len).filter(i -> t[p + i] != '*').peek(i -> t[p + i] = '*').count();
return stars;
}
}
解释
方法:
这个题解采用了回溯的思路。从目标字符串的左端开始,先找到与印章开头相同的部分,然后递归地寻找右边剩余部分的合法分割。如果找不到,就回溯尝试更短的开头。当找到一个与印章完全相同的子串时,转而从右端开始寻找与印章结尾相同的部分,直到找到一个完整的合法分割。在回溯的过程中,用一个集合记录所有不能完成的开头坐标,避免重复搜索。
时间复杂度:
O(m^(n/m))
空间复杂度:
O(n^2/m)
代码细节讲解
🦆
在递归函数`recurtion`中,你是如何确保每次调用都能有效地减少问题的规模,从而避免无限递归?
▷🦆
函数`left`在寻找开头与stamp相同部分时,如果完全匹配的长度小于stamp的长度,这种部分匹配对整体解决方案有何影响?
▷🦆
为什么在处理结尾相同的部分时,需要从右向左递归搜索,而不是继续从左向右?这样的方向变换对算法的效率和结果有什么具体影响?
▷