-
Notifications
You must be signed in to change notification settings - Fork 0
/
string_anagrams_test.go
99 lines (79 loc) · 2.01 KB
/
string_anagrams_test.go
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/*
Problem:
- Given a string and a pattern, find all anagrams of the pattern in the given string
- Return them as a list of anagrams' starting indices.
Example:
- Input: string="ppqp", pattern="pq"
Output: []int{1, 2}
- Input: string="abbcabc", pattern="abc"
Output: []int{2, 3, 4}
Approach:
- Similar to permutation in string problem, except we will store the starting indices
of the anagrams of the pattern.
Cost:
- O(n) time, O(m) space where m is the number of distinct characters in the map.
*/
package gtci
import (
"testing"
"github.com/pcaruana/algo/common"
)
func TestFindStringAnagrams(t *testing.T) {
tests := []struct {
in1 string
in2 string
expected []int
}{
{"ppqp", "pq", []int{1, 2}},
{"abbcabc", "abc", []int{2, 3, 4}},
}
for _, tt := range tests {
common.Equal(
t,
tt.expected,
findStringAnagrams(tt.in1, tt.in2),
)
}
}
func findStringAnagrams(s string, pattern string) []int {
out := []int{}
matched, start := 0, 0
// char keeps track of characters' frequencies.
char := map[string]int{}
// calculate the frequencies of all characters in the pattern.
for _, c := range pattern {
if _, ok := char[string(c)]; !ok {
char[string(c)] = 0
}
char[string(c)]++
}
for end := range s {
// if the character matches one in the map, decrease its frequency.
// if its frequency becomes 0, we have a complete match.
endChar := string(s[end])
if _, ok := char[endChar]; ok {
char[endChar]--
if char[endChar] == 0 {
matched++
}
}
// return true immediately if we have all complete matches.
if matched == len(char) {
out = append(out, start)
}
// shrink the window by one character at a time so that its size is
// equal to the length of the pattern.
if end >= len(pattern)-1 {
startChar := string(s[start])
start++
// if the character going out is part of the pattern, put it back in.
if _, ok := char[startChar]; ok {
if char[startChar] == 0 {
matched--
}
char[startChar]++
}
}
}
return out
}