Перестановка строки
Условие задачи
Даны строка и шаблон из ASCII-символов. Определите, содержит ли строка какую-либо перестановку символов шаблона.
Перестановка получается изменением порядка символов. Например, у строки abc есть шесть перестановок: abc, acb, bac, bca, cab и cba.
Пример 1:
1
2
3
Вход: строка="oidbcaf", шаблон="abc"
Выход: true
Пояснение: строка содержит "bca" — перестановку шаблона.
Пример 2:
1
2
3
Вход: строка="odicf", шаблон="dc"
Выход: false
Пояснение: строка не содержит перестановку шаблона.
Пример 3:
1
2
3
Вход: строка="bcdxabcdy", шаблон="bcdyabcdx"
Выход: true
Пояснение: строка и шаблон являются перестановками друг друга.
Пример 4:
1
2
3
Вход: строка="aaacb", шаблон="abc"
Выход: true
Пояснение: строка содержит перестановку "acb".
Решение
Сначала подсчитаем частоты всех символов шаблона. Затем будем перемещать по строке окно длиной, равной длине шаблона:
- Если входящий символ есть в таблице, уменьшаем его частоту. Нулевая частота означает, что все вхождения этого символа совпали.
- Когда совпали все различные символы шаблона, окно содержит искомую перестановку.
- Достигнув нужного размера окна, удаляем его левый символ. Если этот символ относится к шаблону, восстанавливаем его частоту и при необходимости уменьшаем число полных совпадений.
Код
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main
import "fmt"
func containsPermutation(text, pattern string) bool {
if len(pattern) == 0 || len(pattern) > len(text) {
return false
}
frequencies := make(map[byte]int)
for index := 0; index < len(pattern); index++ {
character := pattern[index]
frequencies[character]++
}
windowStart := 0
matched := 0
for windowEnd := 0; windowEnd < len(text); windowEnd++ {
character := text[windowEnd]
if _, ok := frequencies[character]; ok {
frequencies[character]--
if frequencies[character] == 0 {
matched++
}
}
if matched == len(frequencies) {
return true
}
if windowEnd >= len(pattern)-1 {
leftCharacter := text[windowStart]
windowStart++
if _, ok := frequencies[leftCharacter]; ok {
if frequencies[leftCharacter] == 0 {
matched--
}
frequencies[leftCharacter]++
}
}
}
return false
}
func main() {
fmt.Println("Перестановка существует:", containsPermutation("oidbcaf", "abc"))
fmt.Println("Перестановка существует:", containsPermutation("odicf", "dc"))
fmt.Println("Перестановка существует:", containsPermutation("bcdxabcdy", "bcdyabcdx"))
fmt.Println("Перестановка существует:", containsPermutation("aaacb", "abc"))
}
Вывод:
1
2
3
4
Перестановка существует: true
Перестановка существует: false
Перестановка существует: true
Перестановка существует: true
Временная сложность
Построение таблицы занимает \(O(M)\), а проход по строке — \(O(N)\). Общая временная сложность равна \(O(N+M)\).
Пространственная сложность
В худшем случае все символы шаблона различны, поэтому пространственная сложность равна \(O(M)\).