diff --git a/pkg/find_median_from_data_stream/main.go b/pkg/find_median_from_data_stream/main.go new file mode 100644 index 0000000..17d3b4c --- /dev/null +++ b/pkg/find_median_from_data_stream/main.go @@ -0,0 +1,82 @@ +package findmedianfromdatastream + +import "container/heap" + +type IntHeap []int + +func (h IntHeap) Len() int { return len(h) } +func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] } +func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } + +func (h *IntHeap) Push(x any) { + *h = append(*h, x.(int)) +} + +func (h IntHeap) Peek() int { + return h[0] +} + +func (h *IntHeap) Pop() any { + old := *h + x := old[len(old)-1] + *h = old[:len(old)-1] + return x +} + +type MedianFinder struct { + // Positive min-heap of top half of values. + top *IntHeap + // Negative min-heap of bottom half of values. + bottom *IntHeap +} + +func Constructor() MedianFinder { + result := MedianFinder{ + top: &IntHeap{}, + bottom: &IntHeap{}, + } + + heap.Init(result.top) + heap.Init(result.bottom) + return result +} + +func (m *MedianFinder) AddNum(num int) { + if m.bottom.Len() > m.top.Len() { + if -m.bottom.Peek() <= num { + heap.Push(m.top, num) + } else { + val := heap.Pop(m.bottom).(int) + heap.Push(m.top, -val) + heap.Push(m.bottom, -num) + } + } else if m.bottom.Len() < m.top.Len() { + if m.top.Peek() >= num { + heap.Push(m.bottom, -num) + } else { + val := heap.Pop(m.top).(int) + heap.Push(m.bottom, -val) + heap.Push(m.top, num) + } + } else { + if m.top.Len() == 0 { + heap.Push(m.top, num) + } else { + if median := m.FindMedian(); float64(num) > median { + heap.Push(m.top, num) + } else { + heap.Push(m.bottom, -num) + } + } + } +} + +func (m *MedianFinder) FindMedian() float64 { + if m.bottom.Len() > m.top.Len() { + return float64(-m.bottom.Peek()) + } else if m.bottom.Len() < m.top.Len() { + return float64(m.top.Peek()) + } else { + return float64(m.top.Peek()-m.bottom.Peek()) / 2.0 + } +} diff --git a/pkg/word_search_ii/main.go b/pkg/word_search_ii/main.go new file mode 100644 index 0000000..a460174 --- /dev/null +++ b/pkg/word_search_ii/main.go @@ -0,0 +1,116 @@ +package wordsearchii + +type State struct { + X, Y int + Previous *State +} + +func (s *State) Visited(x, y int) bool { + if s == nil { + return false + } + + if s.X == x && s.Y == y { + return true + } + + return s.Previous.Visited(x, y) +} + +type Trie struct { + Children map[byte]*Trie + States []*State +} + +func NewTrie(board [][]byte) *Trie { + trie := &Trie{ + Children: map[byte]*Trie{}, + States: []*State{}, + } + + for x := range board { + for y := range board[x] { + if _, ok := trie.Children[board[x][y]]; !ok { + trie.Children[board[x][y]] = &Trie{ + Children: map[byte]*Trie{}, + States: []*State{}, + } + } + + trie.Children[board[x][y]].States = append(trie.Children[board[x][y]].States, &State{ + X: x, + Y: y, + Previous: nil, + }) + } + } + + return trie +} + +var CardinalDirections = [][2]int{ + {-1, 0}, + {1, 0}, + {0, -1}, + {0, 1}, +} + +func (t *Trie) Explore(board [][]byte, ch byte) *Trie { + child := &Trie{ + Children: map[byte]*Trie{}, + States: []*State{}, + } + + for _, state := range t.States { + for _, direction := range CardinalDirections { + xNew, yNew := state.X+direction[0], state.Y+direction[1] + + if xNew < 0 || xNew >= len(board) || yNew < 0 || yNew >= len(board[xNew]) { + continue + } + + if state.Visited(xNew, yNew) { + continue + } + + if ch != board[xNew][yNew] { + continue + } + + child.States = append(child.States, &State{ + X: xNew, + Y: yNew, + Previous: state, + }) + } + } + + t.Children[ch] = child + return child +} + +func (t *Trie) FindWord(board [][]byte, word string) bool { + if len(word) == 0 { + return len(t.States) > 0 + } + + child, ok := t.Children[word[0]] + if !ok { + child = t.Explore(board, word[0]) + } + + return child.FindWord(board, word[1:]) +} + +func FindWords(board [][]byte, words []string) []string { + trie := NewTrie(board) + found := []string{} + + for _, word := range words { + if trie.FindWord(board, word) { + found = append(found, word) + } + } + + return found +}