Skip to content

Commit cbf61d7

Browse files
Up to design-hit-counter
1 parent 25a30e7 commit cbf61d7

8 files changed

+787
-0
lines changed

design-hit-counter.go

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
const (
8+
MaxNumCounts = 300
9+
)
10+
11+
type HitCounter struct {
12+
head int
13+
vHead int
14+
tail int
15+
vTail int
16+
counts []int
17+
}
18+
19+
/** Initialize your data structure here. */
20+
func Constructor() HitCounter {
21+
return HitCounter{
22+
head: MaxNumCounts - 1,
23+
vHead: MaxNumCounts,
24+
tail: 0,
25+
vTail: 1,
26+
counts: make([]int, MaxNumCounts),
27+
}
28+
}
29+
30+
func (this *HitCounter) resetCounts() {
31+
for i, _ := range this.counts {
32+
this.counts[i] = 0
33+
}
34+
}
35+
36+
func (this *HitCounter) sum() int {
37+
s := 0
38+
39+
for _, c := range this.counts {
40+
s += c
41+
}
42+
43+
return s
44+
}
45+
46+
/** Record a hit.
47+
@param timestamp - The current timestamp (in seconds granularity). */
48+
func (this *HitCounter) Hit(timestamp int) {
49+
if timestamp-this.vHead >= MaxNumCounts {
50+
this.resetCounts()
51+
this.head = MaxNumCounts - 1
52+
this.tail = 0
53+
this.vHead = timestamp
54+
this.vTail = this.vHead - MaxNumCounts + 1
55+
this.counts[this.head] += 1
56+
57+
return
58+
}
59+
60+
if this.vHead < timestamp {
61+
for this.vHead < timestamp {
62+
this.vHead++
63+
this.vTail++
64+
65+
this.head = (this.head + 1) % MaxNumCounts
66+
this.tail = (this.tail + 1) % MaxNumCounts
67+
68+
this.counts[this.head] = 0
69+
}
70+
71+
this.counts[this.head] = 1
72+
73+
return
74+
}
75+
76+
// this.vHead >= timestamp
77+
offset2 := (this.tail + (timestamp - this.vTail)) % MaxNumCounts
78+
this.counts[offset2] += 1
79+
}
80+
81+
/** Return the number of hits in the past 5 minutes.
82+
@param timestamp - The current timestamp (in seconds granularity).
83+
*/
84+
func (this *HitCounter) GetHits(timestamp int) int {
85+
if timestamp-this.vHead >= MaxNumCounts {
86+
this.resetCounts()
87+
this.head = MaxNumCounts - 1
88+
this.tail = 0
89+
this.vHead = timestamp
90+
this.vTail = this.vHead - MaxNumCounts + 1
91+
92+
return 0
93+
}
94+
95+
if this.vHead < timestamp {
96+
for this.vHead < timestamp {
97+
this.vHead++
98+
this.vTail++
99+
100+
this.head = (this.head + 1) % MaxNumCounts
101+
this.tail = (this.tail + 1) % MaxNumCounts
102+
103+
this.counts[this.head] = 0
104+
}
105+
106+
this.counts[this.head] = 0
107+
108+
return this.sum()
109+
}
110+
111+
// this.vHead >= timestamp
112+
return this.sum()
113+
}
114+
115+
/**
116+
* Your HitCounter object will be instantiated and called as such:
117+
* obj := Constructor();
118+
* obj.Hit(timestamp);
119+
* param_2 := obj.GetHits(timestamp);
120+
*/
121+
122+
func test1() {
123+
hc := Constructor()
124+
125+
hc.Hit(1)
126+
hc.Hit(2)
127+
hc.Hit(3)
128+
fmt.Printf("getHits(4) = %d (expected: 3)\n", hc.GetHits(4))
129+
130+
hc.Hit(300)
131+
fmt.Printf("getHits(300) = %d (expected: 4)\n", hc.GetHits(300))
132+
133+
fmt.Printf("getHits(301) = %d (expected: 3)\n", hc.GetHits(301))
134+
}
135+
136+
func test2() {
137+
hc := Constructor()
138+
139+
hc.Hit(1)
140+
hc.Hit(1)
141+
hc.Hit(1)
142+
hc.Hit(300)
143+
fmt.Printf("getHits(300) = %d (expected: 4)\n", hc.GetHits(300))
144+
145+
hc.Hit(300)
146+
fmt.Printf("getHits(300) = %d (expected: 5)\n", hc.GetHits(300))
147+
148+
hc.Hit(301)
149+
fmt.Printf("getHits(301) = %d (expected: 3)\n", hc.GetHits(301))
150+
}
151+
152+
func main() {
153+
test1()
154+
// test2()
155+
}

edit-distance.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package main
2+
3+
func min2(a, b int) int {
4+
if a < b {
5+
return a
6+
}
7+
8+
return b
9+
}
10+
11+
func min3(a, b, c int) int {
12+
return min2(a, min2(b, c))
13+
}
14+
15+
func minDistance(word1 string, word2 string) int {
16+
w1Chars, w2Chars := []rune(word1), []rune(word2)
17+
w1Len, w2Len := len(w1Chars), len(w2Chars)
18+
mat := make([][]int, w1Len+1)
19+
20+
for i, _ := range mat {
21+
mat[i] = make([]int, w2Len+1)
22+
}
23+
24+
// mat[i][j]: the minimum number of edits neeed to transform
25+
// word1's i-prefix (prefix of length i) to word2's j-prefix
26+
// (prefix of length j)
27+
for i := 0; i <= w1Len; i++ {
28+
mat[i][0] = i
29+
}
30+
31+
for j := 0; j <= w2Len; j++ {
32+
mat[0][j] = j
33+
}
34+
35+
for i := 1; i <= w1Len; i++ {
36+
for j := 1; j <= w2Len; j++ {
37+
if w1Chars[i-1] == w2Chars[j-1] {
38+
mat[i][j] = mat[i-1][j-1]
39+
40+
continue
41+
}
42+
43+
mat[i][j] = min3(1+mat[i-1][j-1], 1+mat[i-1][j], 1+mat[i][j-1])
44+
}
45+
}
46+
47+
return mat[w1Len][w2Len]
48+
}
49+
50+
func main() {
51+
52+
}

find-all-anagrams-in-a-string.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func dumpNonZeroCounts(counts []int) {
8+
for i, count := range counts {
9+
if count == 0 {
10+
continue
11+
}
12+
13+
fmt.Printf("%c: %d; ", rune(i), count)
14+
}
15+
16+
fmt.Println()
17+
}
18+
19+
func findAnagrams(s string, p string) []int {
20+
if len(s) < len(p) {
21+
return []int{}
22+
}
23+
24+
pChars := []rune(p)
25+
sChars := []rune(s)
26+
pCharCounts := make([]int, 256)
27+
sWindowCharCounts := make([]int, 256)
28+
29+
for _, pChar := range pChars {
30+
pCharCounts[pChar] += 1
31+
}
32+
33+
for i := 0; i < len(pChars); i++ {
34+
sWindowCharCounts[sChars[i]] += 1
35+
}
36+
37+
numDiffs := 0
38+
39+
for i := 0; i < len(pCharCounts); i++ {
40+
if pCharCounts[i] != sWindowCharCounts[i] {
41+
numDiffs++
42+
}
43+
}
44+
45+
start, end := 0, len(pChars)-1
46+
anagramOffsets := make([]int, 0, len(pChars))
47+
48+
for end < len(sChars) {
49+
if numDiffs == 0 {
50+
anagramOffsets = append(anagramOffsets, start)
51+
}
52+
53+
sWindowCharCounts[sChars[start]]--
54+
55+
if sWindowCharCounts[sChars[start]] == pCharCounts[sChars[start]] {
56+
numDiffs--
57+
} else if sWindowCharCounts[sChars[start]]+1 == pCharCounts[sChars[start]] {
58+
numDiffs++
59+
}
60+
61+
start++
62+
63+
end++
64+
65+
if end >= len(sChars) {
66+
break
67+
}
68+
69+
sWindowCharCounts[sChars[end]]++
70+
71+
if sWindowCharCounts[sChars[end]] == pCharCounts[sChars[end]] {
72+
numDiffs--
73+
} else if sWindowCharCounts[sChars[end]]-1 == pCharCounts[sChars[end]] {
74+
numDiffs++
75+
}
76+
77+
// fmt.Printf("At start=%d: ", start)
78+
// dumpNonZeroCounts(sWindowCharCounts)
79+
}
80+
81+
return anagramOffsets
82+
}
83+
84+
type testcase struct {
85+
s string
86+
p string
87+
expectedResult []int
88+
}
89+
90+
func slicesEqual(a, b []int) bool {
91+
if len(a) != len(b) {
92+
return false
93+
}
94+
95+
for i, n := range a {
96+
if n != b[i] {
97+
return false
98+
}
99+
}
100+
101+
return true
102+
}
103+
104+
func runTests() {
105+
testcases := []testcase{
106+
testcase{"cbaebabacd", "abc", []int{0, 6}},
107+
testcase{"abab", "ab", []int{0, 1, 2}},
108+
}
109+
110+
for i, tc := range testcases {
111+
result := findAnagrams(tc.s, tc.p)
112+
113+
if !slicesEqual(result, tc.expectedResult) {
114+
fmt.Printf("Test %d failed; expected: %v; got %v\n", i, tc.expectedResult, result)
115+
}
116+
}
117+
}
118+
119+
func main() {
120+
runTests()
121+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func min2(a, b int) int {
6+
if a < b {
7+
return a
8+
}
9+
10+
return b
11+
}
12+
13+
func min3(a, b, c int) int {
14+
return min2(a, min2(b, c))
15+
}
16+
17+
func minDistance(word1 string, word2 string) int {
18+
w1Chars, w2Chars := []rune(word1), []rune(word2)
19+
w1Len, w2Len := len(w1Chars), len(w2Chars)
20+
mat := make([][]int, w1Len+1)
21+
22+
for i, _ := range mat {
23+
mat[i] = make([]int, w2Len+1)
24+
}
25+
26+
// mat[i][j]: the minimum number of edits neeed to transform
27+
// word1's i-prefix (prefix of length i) to word2's j-prefix
28+
// (prefix of length j)
29+
for i := 0; i <= w1Len; i++ {
30+
mat[i][0] = i
31+
}
32+
33+
for j := 0; j <= w2Len; j++ {
34+
mat[0][j] = j
35+
}
36+
37+
for i := 1; i <= w1Len; i++ {
38+
for j := 1; j <= w2Len; j++ {
39+
if w1Chars[i-1] == w2Chars[j-1] {
40+
mat[i][j] = mat[i-1][j-1]
41+
42+
continue
43+
}
44+
45+
mat[i][j] = min3(1+mat[i-1][j-1], 1+mat[i-1][j], 1+mat[i][j-1])
46+
}
47+
}
48+
49+
return mat[w1Len][w2Len]
50+
}
51+
52+
func runTests() {
53+
fmt.Printf("edits: %d\n", minDistance("abbac", "cabba"))
54+
fmt.Printf("edits: %d\n", minDistance("abcdecba", "abcedcba"))
55+
fmt.Printf("edits: %d\n", minDistance("abcdeca", "acedcba"))
56+
57+
}
58+
59+
func main() {
60+
runTests()
61+
}

0 commit comments

Comments
 (0)