Skip to content

Commit 5b79905

Browse files
authored
feat: add solutions to lc problem: No.0936 (doocs#2045)
No.0936.Stamping The Sequence
1 parent a1fec59 commit 5b79905

File tree

8 files changed

+859
-2
lines changed

8 files changed

+859
-2
lines changed

solution/0900-0999/0936.Stamping The Sequence/README.md

Lines changed: 300 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,321 @@
4848

4949
<!-- 这里可写通用的实现逻辑 -->
5050

51+
**方法一:逆向思维 + 拓扑排序**
52+
53+
如果我们正向地对序列进行操作,那么处理起来会比较麻烦,因为后续的操作会把前面的操作覆盖掉。我们不妨考虑逆向地对序列进行操作,即从目标字符串 $target$ 开始,考虑将 $target$ 变成 $?????$ 的过程。
54+
55+
我们不妨记字母印章的长度为 $m$,目标字符串的长度为 $n$。如果我们拿着字母印章在目标字符串上操作,那么一共有 $n-m+1$ 个开始位置可以放置字母印章。我们可以枚举这 $n-m+1$ 个开始位置,利用类似拓扑排序的方法,逆向地进行操作。
56+
57+
首先,我们明确,每个开始位置都对应着一个长度为 $m$ 的窗口。
58+
59+
接下来,我们定义以下数据结构或变量,其中:
60+
61+
- 入度数组 $indeg$,其中 $indeg[i]$ 表示第 $i$ 个窗口中有多少位置的字符与字母印章中的字符不同,初始时,$indeg[i]=m$。若 $indeg[i]=0$,说明第 $i$ 个窗口中的字符都与字母印章中的字符相同,那么我们就可以在第 $i$ 个窗口中放置字母印章。
62+
- 邻接表 $g$,其中 $g[i]$ 表示目标字符串 $target$ 的第 $i$ 个位置上,所有与字母印章存在不同字符的窗口的集合。
63+
- 队列 $q$,用于存储所有入度为 $0$ 的窗口的编号。
64+
- 数组 $vis$,用于标记目标字符串 $target$ 的每个位置是否已经被覆盖。
65+
- 数组 $ans$,用于存储答案。
66+
67+
接下来,我们进行拓扑排序。在拓扑排序的每一步中,我们取出队首的窗口编号 $i$,并将 $i$ 放入答案数组 $ans$ 中。然后,我们枚举字母印章中的每个位置 $j$,如果第 $i$ 个窗口中的第 $j$ 个位置未被覆盖,那么我们就将其覆盖,并将 $indeg$ 数组中所有与第 $i$ 个窗口中的第 $j$ 个位置相同的窗口的入度减少 $1$。如果某个窗口的入度变为 $0$,那么我们就将其放入队列 $q$ 中等待下一次处理。
68+
69+
在拓扑排序结束后,如果目标字符串 $target$ 的每个位置都被覆盖,那么答案数组 $ans$ 中存储的就是我们要求的答案。否则,目标字符串 $target$ 无法被覆盖,我们就返回一个空数组。
70+
71+
时间复杂度 $O(n \times (n - m + 1))$,空间复杂度 $O(n \times (n - m + 1))$。其中 $n$ 和 $m$ 分别是目标字符串 $target$ 和字母印章的长度。
72+
5173
<!-- tabs:start -->
5274

5375
### **Python3**
5476

5577
<!-- 这里可写当前语言的特殊实现逻辑 -->
5678

5779
```python
58-
80+
class Solution:
81+
def movesToStamp(self, stamp: str, target: str) -> List[int]:
82+
m, n = len(stamp), len(target)
83+
indeg = [m] * (n - m + 1)
84+
q = deque()
85+
g = [[] for _ in range(n)]
86+
for i in range(n - m + 1):
87+
for j, c in enumerate(stamp):
88+
if target[i + j] == c:
89+
indeg[i] -= 1
90+
if indeg[i] == 0:
91+
q.append(i)
92+
else:
93+
g[i + j].append(i)
94+
ans = []
95+
vis = [False] * n
96+
while q:
97+
i = q.popleft()
98+
ans.append(i)
99+
for j in range(m):
100+
if not vis[i + j]:
101+
vis[i + j] = True
102+
for k in g[i + j]:
103+
indeg[k] -= 1
104+
if indeg[k] == 0:
105+
q.append(k)
106+
return ans[::-1] if all(vis) else []
59107
```
60108

61109
### **Java**
62110

63111
<!-- 这里可写当前语言的特殊实现逻辑 -->
64112

65113
```java
114+
class Solution {
115+
public int[] movesToStamp(String stamp, String target) {
116+
int m = stamp.length(), n = target.length();
117+
int[] indeg = new int[n - m + 1];
118+
Arrays.fill(indeg, m);
119+
List<Integer>[] g = new List[n];
120+
Arrays.setAll(g, i -> new ArrayList<>());
121+
Deque<Integer> q = new ArrayDeque<>();
122+
for (int i = 0; i < n - m + 1; ++i) {
123+
for (int j = 0; j < m; ++j) {
124+
if (target.charAt(i + j) == stamp.charAt(j)) {
125+
if (--indeg[i] == 0) {
126+
q.offer(i);
127+
}
128+
} else {
129+
g[i + j].add(i);
130+
}
131+
}
132+
}
133+
List<Integer> ans = new ArrayList<>();
134+
boolean[] vis = new boolean[n];
135+
while (!q.isEmpty()) {
136+
int i = q.poll();
137+
ans.add(i);
138+
for (int j = 0; j < m; ++j) {
139+
if (!vis[i + j]) {
140+
vis[i + j] = true;
141+
for (int k : g[i + j]) {
142+
if (--indeg[k] == 0) {
143+
q.offer(k);
144+
}
145+
}
146+
}
147+
}
148+
}
149+
for (int i = 0; i < n; ++i) {
150+
if (!vis[i]) {
151+
return new int[0];
152+
}
153+
}
154+
Collections.reverse(ans);
155+
return ans.stream().mapToInt(Integer::intValue).toArray();
156+
}
157+
}
158+
```
159+
160+
### **C++**
161+
162+
```cpp
163+
class Solution {
164+
public:
165+
vector<int> movesToStamp(string stamp, string target) {
166+
int m = stamp.size(), n = target.size();
167+
vector<int> indeg(n - m + 1, m);
168+
vector<int> g[n];
169+
queue<int> q;
170+
for (int i = 0; i < n - m + 1; ++i) {
171+
for (int j = 0; j < m; ++j) {
172+
if (target[i + j] == stamp[j]) {
173+
if (--indeg[i] == 0) {
174+
q.push(i);
175+
}
176+
} else {
177+
g[i + j].push_back(i);
178+
}
179+
}
180+
}
181+
vector<int> ans;
182+
vector<bool> vis(n);
183+
while (q.size()) {
184+
int i = q.front();
185+
q.pop();
186+
ans.push_back(i);
187+
for (int j = 0; j < m; ++j) {
188+
if (!vis[i + j]) {
189+
vis[i + j] = true;
190+
for (int k : g[i + j]) {
191+
if (--indeg[k] == 0) {
192+
q.push(k);
193+
}
194+
}
195+
}
196+
}
197+
}
198+
for (int i = 0; i < n; ++i) {
199+
if (!vis[i]) {
200+
return {};
201+
}
202+
}
203+
reverse(ans.begin(), ans.end());
204+
return ans;
205+
}
206+
};
207+
```
208+
209+
### **Go**
210+
211+
```go
212+
func movesToStamp(stamp string, target string) (ans []int) {
213+
m, n := len(stamp), len(target)
214+
indeg := make([]int, n-m+1)
215+
for i := range indeg {
216+
indeg[i] = m
217+
}
218+
g := make([][]int, n)
219+
q := []int{}
220+
for i := 0; i < n-m+1; i++ {
221+
for j := range stamp {
222+
if target[i+j] == stamp[j] {
223+
indeg[i]--
224+
if indeg[i] == 0 {
225+
q = append(q, i)
226+
}
227+
} else {
228+
g[i+j] = append(g[i+j], i)
229+
}
230+
}
231+
}
232+
vis := make([]bool, n)
233+
for len(q) > 0 {
234+
i := q[0]
235+
q = q[1:]
236+
ans = append(ans, i)
237+
for j := range stamp {
238+
if !vis[i+j] {
239+
vis[i+j] = true
240+
for _, k := range g[i+j] {
241+
indeg[k]--
242+
if indeg[k] == 0 {
243+
q = append(q, k)
244+
}
245+
}
246+
}
247+
}
248+
}
249+
for _, v := range vis {
250+
if !v {
251+
return []int{}
252+
}
253+
}
254+
for i, j := 0, len(ans)-1; i < j; i, j = i+1, j-1 {
255+
ans[i], ans[j] = ans[j], ans[i]
256+
}
257+
return
258+
}
259+
```
260+
261+
### **TypeScript**
262+
263+
```ts
264+
function movesToStamp(stamp: string, target: string): number[] {
265+
const m: number = stamp.length;
266+
const n: number = target.length;
267+
const indeg: number[] = Array(n - m + 1).fill(m);
268+
const g: number[][] = Array.from({ length: n }, () => []);
269+
const q: number[] = [];
270+
for (let i = 0; i < n - m + 1; ++i) {
271+
for (let j = 0; j < m; ++j) {
272+
if (target[i + j] === stamp[j]) {
273+
if (--indeg[i] === 0) {
274+
q.push(i);
275+
}
276+
} else {
277+
g[i + j].push(i);
278+
}
279+
}
280+
}
281+
282+
const ans: number[] = [];
283+
const vis: boolean[] = Array(n).fill(false);
284+
while (q.length) {
285+
const i: number = q.shift()!;
286+
ans.push(i);
287+
for (let j = 0; j < m; ++j) {
288+
if (!vis[i + j]) {
289+
vis[i + j] = true;
290+
for (const k of g[i + j]) {
291+
if (--indeg[k] === 0) {
292+
q.push(k);
293+
}
294+
}
295+
}
296+
}
297+
}
298+
if (!vis.every(v => v)) {
299+
return [];
300+
}
301+
ans.reverse();
302+
return ans;
303+
}
304+
```
66305

306+
### **Rust**
307+
308+
```rust
309+
use std::collections::VecDeque;
310+
311+
impl Solution {
312+
pub fn moves_to_stamp(stamp: String, target: String) -> Vec<i32> {
313+
let m = stamp.len();
314+
let n = target.len();
315+
316+
let mut indeg: Vec<usize> = vec![m; n - m + 1];
317+
let mut g: Vec<Vec<usize>> = vec![Vec::new(); n];
318+
let mut q: VecDeque<usize> = VecDeque::new();
319+
320+
for i in 0..n - m + 1 {
321+
for j in 0..m {
322+
if
323+
target
324+
.chars()
325+
.nth(i + j)
326+
.unwrap() == stamp.chars().nth(j).unwrap()
327+
{
328+
indeg[i] -= 1;
329+
if indeg[i] == 0 {
330+
q.push_back(i);
331+
}
332+
} else {
333+
g[i + j].push(i);
334+
}
335+
}
336+
}
337+
338+
let mut ans: Vec<i32> = Vec::new();
339+
let mut vis: Vec<bool> = vec![false; n];
340+
341+
while let Some(i) = q.pop_front() {
342+
ans.push(i as i32);
343+
344+
for j in 0..m {
345+
if !vis[i + j] {
346+
vis[i + j] = true;
347+
348+
for &k in g[i + j].iter() {
349+
indeg[k] -= 1;
350+
if indeg[k] == 0 {
351+
q.push_back(k);
352+
}
353+
}
354+
}
355+
}
356+
}
357+
358+
if vis.iter().all(|&v| v) {
359+
ans.reverse();
360+
ans
361+
} else {
362+
Vec::new()
363+
}
364+
}
365+
}
67366
```
68367

69368
### **...**

0 commit comments

Comments
 (0)