feat: progress

This commit is contained in:
2026-05-23 16:12:24 -04:00
parent 2ca8bb4427
commit dc373fecb5
9 changed files with 660 additions and 11 deletions

View 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)
}

View 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()
}

View File

@@ -6,6 +6,13 @@ import (
func MaxSlidingWindow(nums []int, k int) []int {
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
}

View 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))
})
}
}

View 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)
}

View 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
}

View 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
}

View File

@@ -3,10 +3,12 @@ package heap
import (
"cmp"
"container/heap"
"slices"
)
type Heap[T any] struct {
type Heap[T comparable] struct {
Data []T
Index map[T]map[int]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
}
func NewBy[T any](lessFunc func(a, b T) bool, items ...T) *Heap[T] {
h := &Heap[T]{items, lessFunc}
func NewBy[T comparable](lessFunc func(a, b T) bool, items ...T) *Heap[T] {
h := &Heap[T]{slices.Clone(items), map[T]map[int]bool{}, lessFunc}
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
}
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]) 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)) }
func (h *Heap[T]) Pop() any {
defer func() { h.Data = h.Data[:len(h.Data)-1] }()
return h.Data[len(h.Data)-1]
h.Data[i], h.Data[j] = h.Data[j], h.Data[i]
h.putIndex(h.Data[i], i)
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]
}