记录 LeetCode 中常见的据结构设计
“65. Valid Number”
type State int
type CharType int
const (
STATE_INITIAL State = iota
STATE_INT_SIGN
STATE_INTEGER
STATE_POINT
STATE_POINT_WITHOUT_INT
STATE_FRACTION
STATE_EXP
STATE_EXP_SIGN
STATE_EXP_NUMBER
STATE_END
)
const (
CHAR_NUMBER CharType = iota
CHAR_EXP
CHAR_POINT
CHAR_SIGN
CHAR_ILLEGAL
)
func toCharType(ch byte) CharType {
switch ch {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return CHAR_NUMBER
case 'e', 'E':
return CHAR_EXP
case '.':
return CHAR_POINT
case '+', '-':
return CHAR_SIGN
default:
return CHAR_ILLEGAL
}
}
func isNumber(s string) bool {
transfer := map[State]map[CharType]State{
STATE_INITIAL: map[CharType]State{
CHAR_NUMBER: STATE_INTEGER,
CHAR_POINT: STATE_POINT_WITHOUT_INT,
CHAR_SIGN: STATE_INT_SIGN,
},
STATE_INT_SIGN: map[CharType]State{
CHAR_NUMBER: STATE_INTEGER,
CHAR_POINT: STATE_POINT_WITHOUT_INT,
},
STATE_INTEGER: map[CharType]State{
CHAR_NUMBER: STATE_INTEGER,
CHAR_EXP: STATE_EXP,
CHAR_POINT: STATE_POINT,
},
STATE_POINT: map[CharType]State{
CHAR_NUMBER: STATE_FRACTION,
CHAR_EXP: STATE_EXP,
},
STATE_POINT_WITHOUT_INT: map[CharType]State{
CHAR_NUMBER: STATE_FRACTION,
},
STATE_FRACTION: map[CharType]State{
CHAR_NUMBER: STATE_FRACTION,
CHAR_EXP: STATE_EXP,
},
STATE_EXP: map[CharType]State{
CHAR_NUMBER: STATE_EXP_NUMBER,
CHAR_SIGN: STATE_EXP_SIGN,
},
STATE_EXP_SIGN: map[CharType]State{
CHAR_NUMBER: STATE_EXP_NUMBER,
},
STATE_EXP_NUMBER: map[CharType]State{
CHAR_NUMBER: STATE_EXP_NUMBER,
},
}
state := STATE_INITIAL
for i := 0; i < len(s); i++ {
typ := toCharType(s[i])
if _, ok := transfer[state][typ]; !ok {
return false
} else {
state = transfer[state][typ]
}
}
return state == STATE_INTEGER || state == STATE_POINT || state == STATE_FRACTION || state == STATE_EXP_NUMBER || state == STATE_END
}
“146. LRU Cache” Golang
import "container/list"
type LRUCache struct {
*list.List
m map[int]*list.Element
size int
}
type kv struct {
Key int
Value int
}
func Constructor(capacity int) LRUCache {
return LRUCache{
List: list.New(),
m : make(map[int]*list.Element),
size : capacity,
}
}
func (this *LRUCache) Get(key int) int {
if element, exists := this.m[key]; exists {
this.MoveToBack(element)
return element.Value.(*kv).Value
}
return -1
}
func (this *LRUCache) Put(key int, value int) {
tmpKV := &kv{Key : key, Value : value}
if element, exists := this.m[key]; exists {
element.Value = tmpKV
this.MoveToBack(element)
return
}
element := this.PushBack(tmpKV)
this.m[key] = element
for len(this.m) > this.size {
delete(this.m, this.Front().Value.(*kv).Key)
this.Remove(this.Front())
}
}
“295. Find Median from Data Stream”
type minHeap struct {
sort.IntSlice
}
func (p *minHeap) Push(x interface{}) {
p.IntSlice = append(p.IntSlice, x.(int))
}
func (p *minHeap) Pop() interface{} {
n := len(p.IntSlice)
ret := p.IntSlice[n-1]
p.IntSlice = p.IntSlice[:n-1]
return ret
}
type maxHeap struct {
minHeap
}
func (p *maxHeap) Less(a, b int) bool {
// 这里如果用 !p.Less(a, b) 会造成死循环递归
return !p.minHeap.Less(a, b)
}
type MedianFinder struct {
minH *minHeap
maxH *maxHeap
}
func Constructor() MedianFinder {
return MedianFinder{
minH: &minHeap{},
maxH: &maxHeap{},
}
}
func (this *MedianFinder) AddNum(num int) {
// 首先交换一次元素以确保大小值合理,即 minH 放较大值、maxH 放较小值
heap.Push(this.maxH, num)
heap.Push(this.minH, heap.Pop(this.maxH))
if this.minH.Len() > this.maxH.Len()+1 {
heap.Push(this.maxH, heap.Pop(this.minH))
}
}
func (this *MedianFinder) FindMedian() (ret float64) {
if (this.minH.Len()+this.maxH.Len()) & 1 == 0 {
return float64(this.minH.IntSlice[0]+this.maxH.IntSlice[0])/2
}
return float64(this.minH.IntSlice[0])
}
“380. Insert Delete GetRandom O(1)”
type RandomizedSet struct {
m map[int]int
b []int
}
func Constructor() RandomizedSet {
return RandomizedSet{
m : make(map[int]int),
}
}
func (this *RandomizedSet) Insert(val int) bool {
if _, ok := this.m[val]; ok {
return false
}
this.m[val] = len(this.b)
this.b = append(this.b, val)
return true
}
func (this *RandomizedSet) Remove(val int) bool {
idx, ok := this.m[val]
if !ok {
return false
}
lastVal := this.b[len(this.b)-1]
this.m[lastVal] = idx
this.b[idx] = lastVal
delete(this.m, val)
this.b = this.b[:len(this.b)-1]
return true
}
func (this *RandomizedSet) GetRandom() int {
return this.b[rand.Intn(len(this.b))]
}
“381. Insert Delete GetRandom O(1) - Duplicates allowed”
import "math/rand"
type RandomizedCollection struct {
m map[int]map[int]struct{}
b []int
}
func Constructor() RandomizedCollection {
return RandomizedCollection{
m : make(map[int]map[int]struct{}),
}
}
func (this *RandomizedCollection) Insert(val int) bool {
_, ok := this.m[val]
if !ok {
this.m[val] = make(map[int]struct{})
}
this.m[val][len(this.b)] = struct{}{}
this.b = append(this.b, val)
return !ok
}
func (this *RandomizedCollection) Remove(val int) bool {
set, ok := this.m[val]
if !ok {
return false
}
var tarDelIdx int
for k := range set {
tarDelIdx = k
break
}
lastVal := this.b[len(this.b)-1]
delete(this.m[lastVal], len(this.b)-1)
delete(set, tarDelIdx)
this.b = this.b[:len(this.b)-1]
if tarDelIdx != len(this.b) {
this.m[lastVal][tarDelIdx] = struct{}{}
this.b[tarDelIdx] = lastVal
}
if len(set) == 0 {
delete(this.m, val)
}
return true
}
func (this *RandomizedCollection) GetRandom() int {
return this.b[rand.Intn(len(this.b))]
}
“460. LFU Cache”
type VFE struct {
v int // value
f int // frequency
e *list.Element // point in list in one frequency
}
type LFUCache struct {
capacity int
minFreq int
k2vfe map[int]*VFE
f2l map[int]*list.List
}
func Constructor(capacity int) LFUCache {
res := LFUCache {
capacity : capacity,
minFreq : 0,
k2vfe : make(map[int]*VFE),
f2l : make(map[int]*list.List),
}
return res
}
func (this *LFUCache) add2List(freq, key int) *list.Element {
if _, exists := this.f2l[freq]; !exists {
this.f2l[freq] = list.New()
}
return this.f2l[freq].PushBack(key)
}
func (this *LFUCache) Get(key int) int {
if vfe, exist := this.k2vfe[key]; exist {
this.f2l[vfe.f].Remove(vfe.e)
vfe.f++
vfe.e = this.add2List(vfe.f, key)
if this.f2l[this.minFreq].Len() == 0 {
this.minFreq++
}
return vfe.v
}
return -1
}
func (this *LFUCache) Put(key int, value int) {
if this.capacity == 0 {
return
}
if vfe, exist := this.k2vfe[key]; exist {
this.f2l[vfe.f].Remove(vfe.e)
if vfe.f == this.minFreq && this.f2l[vfe.f].Len() == 0 {
this.minFreq++
}
vfe.f++
vfe.v = value
vfe.e = this.add2List(vfe.f, key)
return
}
if len(this.k2vfe) >= this.capacity {
rmKey := this.f2l[this.minFreq].Front().Value.(int)
delete(this.k2vfe, rmKey)
this.f2l[this.minFreq].Remove(this.f2l[this.minFreq].Front())
}
this.k2vfe[key] = &VFE {
v : value,
f : 1,
e : this.add2List(1, key),
}
this.minFreq = 1
}
“480. Sliding Window Median”
type hp struct {
sort.IntSlice
size int // 有效元素数量
delayDelMap map[int]int
isBigHeap bool // true 表示最大堆,保存负数;默认 false 表示最小堆
}
func (p *hp) Push(x interface{}) {
p.IntSlice = append(p.IntSlice, x.(int))
}
func (p *hp) Pop() interface{} {
ret := p.IntSlice[p.Len()-1]
p.IntSlice = p.IntSlice[:p.Len()-1]
return ret
}
func (p *hp) push(x int) {
p.size++
heap.Push(p, x)
}
func (p *hp) pop() int {
p.size--
return heap.Pop(p).(int)
}
func (p *hp) prune() {
// prune 时 size 不变
for p.Len() > 0 {
num := p.IntSlice[0]
if p.isBigHeap {
num = -num
}
if d, has := p.delayDelMap[num]; has {
if d > 1 {
p.delayDelMap[num]--
} else {
delete(p.delayDelMap, num)
}
heap.Pop(p)
} else {
break
}
}
}
type slidingWindow struct {
smallHeap *hp // 较小元素,是最大堆,放负数
largeHeap *hp
delayDelMap map[int]int
windowSize int
}
func NewWindow(size int) *slidingWindow {
m := make(map[int]int)
return &slidingWindow{
smallHeap: &hp{delayDelMap: m, isBigHeap: true},
largeHeap: &hp{delayDelMap: m},
delayDelMap: m,
windowSize: size,
}
}
func (p *slidingWindow) makeBalance() {
if p.smallHeap.size > p.largeHeap.size+1 { // 较小数堆元素允许偏多1
p.largeHeap.push(-p.smallHeap.pop())
p.smallHeap.prune()
} else if p.largeHeap.size > p.smallHeap.size {
p.smallHeap.push(-p.largeHeap.pop())
p.largeHeap.prune()
}
}
func (p *slidingWindow) insert(num int) {
if p.smallHeap.Len() == 0 || num <= -p.smallHeap.IntSlice[0] {
p.smallHeap.push(-num)
} else {
p.largeHeap.push(num)
}
p.makeBalance()
}
func (p *slidingWindow) erase(num int) {
p.delayDelMap[num]++
if num <= -p.smallHeap.IntSlice[0] {
p.smallHeap.size--
p.smallHeap.prune()
} else {
p.largeHeap.size--
p.largeHeap.prune()
}
p.makeBalance()
}
func (p *slidingWindow) getMedian() float64 {
if p.windowSize & 1 > 0 {
return float64(-p.smallHeap.IntSlice[0])
} else {
return float64(-p.smallHeap.IntSlice[0]+p.largeHeap.IntSlice[0])/2
}
}
func medianSlidingWindow(nums []int, k int) []float64 {
n := len(nums)
sw := NewWindow(k)
for _, v := range nums[:k] {
sw.insert(v)
}
ret := make([]float64, 0, n-k+1)
ret = append(ret, sw.getMedian())
for i := k; i < n; i++ {
sw.insert(nums[i])
sw.erase(nums[i-k])
//fmt.Println("insert",nums[i],"erase",nums[i-k],"ret", sw.getMedian(),sw.delayDelMap,sw.smallHeap.IntSlice,sw.largeHeap.IntSlice)
ret = append(ret, sw.getMedian())
}
return ret
}