feat: progress
This commit is contained in:
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
|||||||
module git.maximhutz.com/practice
|
module git.maximhutz.com/practice
|
||||||
|
|
||||||
go 1.24.10
|
go 1.26
|
||||||
|
|
||||||
require github.com/stretchr/testify v1.11.1
|
require github.com/stretchr/testify v1.11.1
|
||||||
|
|
||||||
|
|||||||
106
pkg/questions/design_twitter/main.go
Normal file
106
pkg/questions/design_twitter/main.go
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
package design_twitter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/heap"
|
||||||
|
"maps"
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TweetHeap [][]Tweet
|
||||||
|
|
||||||
|
func (h TweetHeap) Len() int { return len(h) }
|
||||||
|
func (h TweetHeap) Less(i, j int) bool {
|
||||||
|
timeI, timeJ := -1, -1
|
||||||
|
|
||||||
|
if len(h[i]) > 0 {
|
||||||
|
timeI = h[i][len(h[i])-1].Time
|
||||||
|
}
|
||||||
|
if len(h[j]) > 0 {
|
||||||
|
timeJ = h[j][len(h[i])-1].Time
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeI > timeJ
|
||||||
|
}
|
||||||
|
func (h TweetHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||||
|
|
||||||
|
func (h *TweetHeap) Push(x any) {
|
||||||
|
*h = append(*h, x.([]Tweet))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TweetHeap) Pop() any {
|
||||||
|
old := *h
|
||||||
|
x := old[len(old)-1]
|
||||||
|
*h = old[:len(old)-1]
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
type Tweet struct {
|
||||||
|
ID int
|
||||||
|
Time int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Twitter struct {
|
||||||
|
tweets map[int][]Tweet
|
||||||
|
follows map[int]map[int]bool
|
||||||
|
counter int
|
||||||
|
}
|
||||||
|
|
||||||
|
func Constructor() Twitter {
|
||||||
|
return Twitter{
|
||||||
|
tweets: map[int][]Tweet{},
|
||||||
|
follows: map[int]map[int]bool{},
|
||||||
|
counter: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Twitter) PostTweet(userId int, tweetId int) {
|
||||||
|
t.counter++
|
||||||
|
|
||||||
|
t.tweets[userId] = append(t.tweets[userId], Tweet{
|
||||||
|
ID: tweetId,
|
||||||
|
Time: t.counter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Twitter) GetNewsFeed(userId int) []int {
|
||||||
|
users := slices.AppendSeq([]int{userId}, maps.Keys(t.follows[userId]))
|
||||||
|
|
||||||
|
hp := TweetHeap{}
|
||||||
|
for _, user := range users {
|
||||||
|
hp = append(hp, t.tweets[user])
|
||||||
|
}
|
||||||
|
heap.Init(&hp)
|
||||||
|
|
||||||
|
feed := []int{}
|
||||||
|
for range 10 {
|
||||||
|
if len(hp[0]) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
top, rest := hp[0][len(hp[0])-1], hp[0][:len(hp[0])-1]
|
||||||
|
feed = append(feed, top.ID)
|
||||||
|
hp[0] = rest
|
||||||
|
|
||||||
|
heap.Fix(&hp, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return feed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Twitter) Follow(followerId int, followeeId int) {
|
||||||
|
if _, ok := t.follows[followerId]; !ok {
|
||||||
|
t.follows[followerId] = map[int]bool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.follows[followerId][followeeId] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Twitter) Unfollow(followerId int, followeeId int) {
|
||||||
|
if _, ok := t.follows[followerId]; !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(t.follows[followerId], followeeId)
|
||||||
|
}
|
||||||
51
pkg/questions/kth_largest_element_in_stream/main.go
Normal file
51
pkg/questions/kth_largest_element_in_stream/main.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package kthlargestelementinstream
|
||||||
|
|
||||||
|
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 KthLargest struct {
|
||||||
|
k int
|
||||||
|
largest IntHeap
|
||||||
|
}
|
||||||
|
|
||||||
|
func Constructor(k int, nums []int) KthLargest {
|
||||||
|
result := KthLargest{k, IntHeap{}}
|
||||||
|
heap.Init(&result.largest)
|
||||||
|
|
||||||
|
for _, n := range nums {
|
||||||
|
result.Add(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *KthLargest) Add(val int) int {
|
||||||
|
heap.Push(&this.largest, val)
|
||||||
|
if this.largest.Len() > this.k {
|
||||||
|
heap.Pop(&this.largest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.largest.Peek()
|
||||||
|
}
|
||||||
@@ -6,6 +6,13 @@ import (
|
|||||||
|
|
||||||
func MaxSlidingWindow(nums []int, k int) []int {
|
func MaxSlidingWindow(nums []int, k int) []int {
|
||||||
h := heap.NewBy(heap.More, nums[:k]...)
|
h := heap.NewBy(heap.More, nums[:k]...)
|
||||||
result := []int{h.Data[0]}
|
result := []int{h.Top()}
|
||||||
|
|
||||||
|
for i := range nums[k:] {
|
||||||
|
h.Drop(nums[i])
|
||||||
|
h.Put(nums[i+k])
|
||||||
|
result = append(result, h.Top())
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
65
pkg/questions/maximum_sliding_window/main_test.go
Normal file
65
pkg/questions/maximum_sliding_window/main_test.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package maximum_sliding_window
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMaxSlidingWindow(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
nums []int
|
||||||
|
k int
|
||||||
|
want []int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "example 1",
|
||||||
|
nums: []int{1, 3, -1, -3, 5, 3, 6, 7},
|
||||||
|
k: 3,
|
||||||
|
want: []int{3, 3, 5, 5, 6, 7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "example 2",
|
||||||
|
nums: []int{1},
|
||||||
|
k: 1,
|
||||||
|
want: []int{1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "k equals length",
|
||||||
|
nums: []int{4, 2, 7, 1},
|
||||||
|
k: 4,
|
||||||
|
want: []int{7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all same",
|
||||||
|
nums: []int{3, 3, 3, 3},
|
||||||
|
k: 2,
|
||||||
|
want: []int{3, 3, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "descending",
|
||||||
|
nums: []int{5, 4, 3, 2, 1},
|
||||||
|
k: 3,
|
||||||
|
want: []int{5, 4, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ascending",
|
||||||
|
nums: []int{1, 2, 3, 4, 5},
|
||||||
|
k: 3,
|
||||||
|
want: []int{3, 4, 5},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negatives",
|
||||||
|
nums: []int{-5, -3, -1, -2, -4},
|
||||||
|
k: 2,
|
||||||
|
want: []int{-3, -1, -1, -2},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tt.want, MaxSlidingWindow(tt.nums, tt.k))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
115
pkg/questions/multiply_strings/main.go
Normal file
115
pkg/questions/multiply_strings/main.go
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package multiplystrings
|
||||||
|
|
||||||
|
func addDigits(a, b byte) (byte, byte) {
|
||||||
|
abInt := int(a-'0') + int(b-'0')
|
||||||
|
return byte(abInt/10) + '0', byte(abInt%10) + '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
func addByDigit(dst *[]byte, src byte) {
|
||||||
|
for i, b := range *dst {
|
||||||
|
if src == '0' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
src, (*dst)[i] = addDigits(b, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
if src != '0' {
|
||||||
|
*dst = append(*dst, src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func add(dst *[]byte, src []byte) {
|
||||||
|
carry := byte('0')
|
||||||
|
|
||||||
|
for i := range max(len(*dst), len(src)) {
|
||||||
|
d, s := byte('0'), byte('0')
|
||||||
|
if len(*dst) > i {
|
||||||
|
d = (*dst)[i]
|
||||||
|
}
|
||||||
|
if len(src) > i {
|
||||||
|
s = src[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
hi, lo := addDigits(d, s)
|
||||||
|
total := []byte{lo, hi}
|
||||||
|
addByDigit(&total, carry)
|
||||||
|
(*dst)[i], carry = total[0], total[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if carry != '0' {
|
||||||
|
*dst = append(*dst, carry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func multiplyDigits(a, b byte) (byte, byte) {
|
||||||
|
abInt := int(a-'0') * int(b-'0')
|
||||||
|
return byte(abInt/10) + '0', byte(abInt%10) + '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
func multiplyByDigit(and []byte, ier byte) []byte {
|
||||||
|
result, carry := []byte{}, byte('0')
|
||||||
|
for _, b := range and {
|
||||||
|
hi, lo := multiplyDigits(b, ier)
|
||||||
|
|
||||||
|
// Fold the incoming carry into the low digit; any overflow rolls
|
||||||
|
// into hi, which is small enough that it never overflows again.
|
||||||
|
c, lo := addDigits(lo, carry)
|
||||||
|
_, carry = addDigits(hi, c)
|
||||||
|
|
||||||
|
result = append(result, lo)
|
||||||
|
}
|
||||||
|
|
||||||
|
if carry != '0' {
|
||||||
|
result = append(result, carry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func reverse(s string) []byte {
|
||||||
|
digits := make([]byte, len(s))
|
||||||
|
for i := range s {
|
||||||
|
digits[len(s)-1-i] = s[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return digits
|
||||||
|
}
|
||||||
|
|
||||||
|
func multiply(a, b string) string {
|
||||||
|
if a == "0" || b == "0" {
|
||||||
|
return "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
and := reverse(a)
|
||||||
|
result := make([]byte, len(a)+len(b))
|
||||||
|
for i := range result {
|
||||||
|
result[i] = '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range len(b) {
|
||||||
|
ier := b[len(b)-1-i]
|
||||||
|
partial := multiplyByDigit(and, ier)
|
||||||
|
|
||||||
|
// Shift left by i places (little-endian: i leading zeros).
|
||||||
|
shifted := make([]byte, i+len(partial))
|
||||||
|
for j := range i {
|
||||||
|
shifted[j] = '0'
|
||||||
|
}
|
||||||
|
copy(shifted[i:], partial)
|
||||||
|
|
||||||
|
add(&result, shifted)
|
||||||
|
}
|
||||||
|
|
||||||
|
end := len(result)
|
||||||
|
for end > 1 && result[end-1] == '0' {
|
||||||
|
end--
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]byte, end)
|
||||||
|
for i := range end {
|
||||||
|
out[i] = result[end-1-i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
167
pkg/questions/n_queens/main.go
Normal file
167
pkg/questions/n_queens/main.go
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
package n_queens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type board [][]bool
|
||||||
|
|
||||||
|
func newBoard(size int) board {
|
||||||
|
b := make([][]bool, size)
|
||||||
|
for i := range b {
|
||||||
|
b[i] = make([]bool, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return board(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b board) size() (int, int) {
|
||||||
|
return len(b[0]), len(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b board) get(x, y int) bool {
|
||||||
|
return b[y][x]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b board) has(x, y int) bool {
|
||||||
|
width, height := b.size()
|
||||||
|
return x >= 0 && y >= 0 && x < width && y < height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b board) set(x, y int, value bool) {
|
||||||
|
b[y][x] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
type position struct{ x, y int }
|
||||||
|
|
||||||
|
type step struct {
|
||||||
|
position int
|
||||||
|
blocked []position
|
||||||
|
}
|
||||||
|
|
||||||
|
type state struct {
|
||||||
|
board board
|
||||||
|
steps []step
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newState(n int) *state {
|
||||||
|
return &state{
|
||||||
|
board: newBoard(n),
|
||||||
|
n: n,
|
||||||
|
steps: make([]step, 0, n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state) options() []int {
|
||||||
|
y := len(s.steps)
|
||||||
|
if y >= s.n {
|
||||||
|
return []int{}
|
||||||
|
}
|
||||||
|
|
||||||
|
results := []int{}
|
||||||
|
for x := range s.n {
|
||||||
|
if s.board.get(x, y) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
results = append(results, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state) forward(x int) {
|
||||||
|
blocked := []position{}
|
||||||
|
y := len(s.steps)
|
||||||
|
|
||||||
|
// Vertical
|
||||||
|
for i := range s.n {
|
||||||
|
if !s.board.get(x, i) {
|
||||||
|
s.board.set(x, i, true)
|
||||||
|
blocked = append(blocked, position{x, i})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal
|
||||||
|
for i := range s.n {
|
||||||
|
if !s.board.get(i, y) {
|
||||||
|
s.board.set(i, y, true)
|
||||||
|
blocked = append(blocked, position{i, y})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward vertical
|
||||||
|
for offset := range s.n {
|
||||||
|
p := position{offset, y + x - offset}
|
||||||
|
|
||||||
|
if s.board.has(p.x, p.y) && !s.board.get(p.x, p.y) {
|
||||||
|
s.board.set(p.x, p.y, true)
|
||||||
|
blocked = append(blocked, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backward vertical
|
||||||
|
for offset := range s.n {
|
||||||
|
p := position{offset, y - x + offset}
|
||||||
|
|
||||||
|
if s.board.has(p.x, p.y) && !s.board.get(p.x, p.y) {
|
||||||
|
s.board.set(p.x, p.y, true)
|
||||||
|
blocked = append(blocked, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.steps = append(s.steps, step{
|
||||||
|
position: x,
|
||||||
|
blocked: blocked,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state) backward() {
|
||||||
|
top, rest := s.steps[len(s.steps)-1], s.steps[:len(s.steps)-1]
|
||||||
|
s.steps = rest
|
||||||
|
|
||||||
|
for _, p := range top.blocked {
|
||||||
|
s.board.set(p.x, p.y, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state) solution() ([]string, bool) {
|
||||||
|
if len(s.steps) != s.n {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
blank := bytes.Repeat([]byte{'.'}, s.n)
|
||||||
|
|
||||||
|
solution := make([]string, s.n)
|
||||||
|
for i := range solution {
|
||||||
|
row := bytes.Clone(blank)
|
||||||
|
row[s.steps[i].position] = 'Q'
|
||||||
|
solution[i] = string(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
return solution, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func SolveNQueens(n int) [][]string {
|
||||||
|
s := newState(n)
|
||||||
|
solutions := [][]string{}
|
||||||
|
|
||||||
|
var dfs func()
|
||||||
|
dfs = func() {
|
||||||
|
if soln, ok := s.solution(); ok {
|
||||||
|
solutions = append(solutions, soln)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range s.options() {
|
||||||
|
s.forward(opt)
|
||||||
|
dfs()
|
||||||
|
s.backward()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dfs()
|
||||||
|
|
||||||
|
return solutions
|
||||||
|
}
|
||||||
60
pkg/questions/word_ladder/main.go
Normal file
60
pkg/questions/word_ladder/main.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package wordladder
|
||||||
|
|
||||||
|
import "iter"
|
||||||
|
|
||||||
|
type wordSet map[string][]string
|
||||||
|
|
||||||
|
func (w wordSet) add(word string) {
|
||||||
|
buffer := []byte(word)
|
||||||
|
for i := range word {
|
||||||
|
buffer[i] = '*'
|
||||||
|
w[string(buffer)] = append(w[string(buffer)], word)
|
||||||
|
buffer[i] = word[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wordSet) neighborsOf(word string) iter.Seq[string] {
|
||||||
|
return func(yield func(string) bool) {
|
||||||
|
buffer := []byte(word)
|
||||||
|
for i := range word {
|
||||||
|
buffer[i] = '*'
|
||||||
|
for _, neighbor := range w[string(buffer)] {
|
||||||
|
yield(neighbor)
|
||||||
|
}
|
||||||
|
buffer[i] = word[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ladderLength(beginWord string, endWord string, wordList []string) int {
|
||||||
|
ws := wordSet{}
|
||||||
|
for _, word := range wordList {
|
||||||
|
ws.add(word)
|
||||||
|
}
|
||||||
|
|
||||||
|
idx, iteration, visited := 0, []string{beginWord}, map[string]bool{}
|
||||||
|
visited[beginWord] = true
|
||||||
|
|
||||||
|
for {
|
||||||
|
nextIteration := []string{}
|
||||||
|
for _, it := range iteration {
|
||||||
|
if it == endWord {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
for neighbor := range ws.neighborsOf(it) {
|
||||||
|
if visited[neighbor] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
visited[neighbor] = true
|
||||||
|
nextIteration = append(nextIteration, neighbor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iteration = nextIteration
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
@@ -3,10 +3,12 @@ package heap
|
|||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
"container/heap"
|
"container/heap"
|
||||||
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Heap[T any] struct {
|
type Heap[T comparable] struct {
|
||||||
Data []T
|
Data []T
|
||||||
|
Index map[T]map[int]bool
|
||||||
lessFunc func(a, b T) bool
|
lessFunc func(a, b T) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,22 +16,98 @@ func More[T cmp.Ordered](x, y T) bool {
|
|||||||
return !cmp.Less(x, y) && x != y
|
return !cmp.Less(x, y) && x != y
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBy[T any](lessFunc func(a, b T) bool, items ...T) *Heap[T] {
|
func NewBy[T comparable](lessFunc func(a, b T) bool, items ...T) *Heap[T] {
|
||||||
h := &Heap[T]{items, lessFunc}
|
h := &Heap[T]{slices.Clone(items), map[T]map[int]bool{}, lessFunc}
|
||||||
heap.Init(h)
|
heap.Init(h)
|
||||||
|
|
||||||
|
for i, v := range h.Data {
|
||||||
|
if h.Index[v] == nil {
|
||||||
|
h.Index[v] = map[int]bool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Index[v][i] = true
|
||||||
|
}
|
||||||
|
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func New[T cmp.Ordered](items ...T) *Heap[T] {
|
func New[T cmp.Ordered](items ...T) *Heap[T] {
|
||||||
return NewBy[T](func(a, b T) bool { return a < b }, items...)
|
return NewBy(func(a, b T) bool { return a < b }, items...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Heap[T]) putIndex(item T, index int) {
|
||||||
|
if h.Index == nil {
|
||||||
|
h.Index = map[T]map[int]bool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Index[item] == nil {
|
||||||
|
h.Index[item] = map[int]bool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Index[item][index] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Heap[T]) dropIndex(item T, index int) {
|
||||||
|
if h.Index == nil {
|
||||||
|
h.Index = map[T]map[int]bool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.Index[item] == nil {
|
||||||
|
h.Index[item] = map[int]bool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(h.Index[item], index)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h Heap[T]) Len() int { return len(h.Data) }
|
func (h Heap[T]) Len() int { return len(h.Data) }
|
||||||
func (h Heap[T]) Less(i, j int) bool { return h.lessFunc(h.Data[i], h.Data[j]) }
|
func (h Heap[T]) Less(i, j int) bool { return h.lessFunc(h.Data[i], h.Data[j]) }
|
||||||
func (h Heap[T]) Swap(i, j int) { h.Data[i], h.Data[j] = h.Data[j], h.Data[i] }
|
func (h Heap[T]) Swap(i, j int) {
|
||||||
|
h.dropIndex(h.Data[i], i)
|
||||||
|
h.dropIndex(h.Data[j], j)
|
||||||
|
|
||||||
func (h *Heap[T]) Push(x any) { h.Data = append(h.Data, x.(T)) }
|
h.Data[i], h.Data[j] = h.Data[j], h.Data[i]
|
||||||
func (h *Heap[T]) Pop() any {
|
|
||||||
defer func() { h.Data = h.Data[:len(h.Data)-1] }()
|
h.putIndex(h.Data[i], i)
|
||||||
return h.Data[len(h.Data)-1]
|
h.putIndex(h.Data[j], j)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Heap[T]) Push(x any) {
|
||||||
|
datum := x.(T)
|
||||||
|
h.Data = append(h.Data, datum)
|
||||||
|
h.putIndex(datum, len(h.Data)-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Heap[T]) Pop() any {
|
||||||
|
index := len(h.Data) - 1
|
||||||
|
datum := h.Data[index]
|
||||||
|
h.dropIndex(datum, index)
|
||||||
|
|
||||||
|
h.Data = h.Data[:index]
|
||||||
|
return datum
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Heap[T]) GetIndex(item T) int {
|
||||||
|
if h.Index[item] == nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
var key int
|
||||||
|
for k := range h.Index[item] {
|
||||||
|
key = k
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Heap[T]) Drop(item T) {
|
||||||
|
heap.Remove(h, h.GetIndex(item))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Heap[T]) Put(item T) {
|
||||||
|
heap.Push(h, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Heap[T]) Top() T {
|
||||||
|
return h.Data[0]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user