Leetcode Note: Go - Design Hashset

Design HashSet - LeetCode
https://leetcode.com/problems/design-hashset/

  • Go 言語で取り組んだメモ

所感

  • MyHashSet クラスを実装する
  • 以下のメソッドを持つ
    • void add(key): hashset に key を追加
    • bool contains(key): hashset に key が存在するか bool で return する
    • void remove(key): hashset から key を削除する

回答

Dynamically modified multi-layer arrays solution in Go - LeetCode Discuss
https://leetcode.com/problems/design-hashset/discuss/482798/Dynamically-modified-multi-layer-arrays-solution-in-Go

const ListCapacity = 10
const HashSize = 4

type MyHashSet struct {
	hashSetData
}

func Constructor() MyHashSet {
	return MyHashSet{}
}

func (m *MyHashSet) Add(key int) {
	_ = m.add(key, 0)
}

func (m *MyHashSet) Remove(key int) {
	_ = m.remove(key, 0)
}

func (m *MyHashSet) Contains(key int) bool {
	return m.contains(key, 0)
}

type hashSetData struct {
	size int
	list []int
	next []MyHashSet
}

func hash(key int, count uint) int {
	return key >> (HashSize * count) & (1<<HashSize - 1)
}

func initList() []int {
	return make([]int, 0, ListCapacity)
}

func initNext() []MyHashSet {
	return make([]MyHashSet, 1<<HashSize)
}

func (h *hashSetData) add(key int, count uint) int {
	var added int
	if h.next != nil {
		added = h.next[hash(key, count)].add(key, count+1)
	} else if len(h.list) != ListCapacity {
		if h.list == nil {
			h.list = initList()
		}
		for _, v := range h.list {
			if v == key {
				return 0
			}
		}
		h.list = append(h.list, key)
		added = 1
	} else {
		h.next = initNext()
		for _, v := range h.list {
			_ = h.next[hash(v, count)].add(v, count+1)
		}
		added = h.next[hash(key, count)].add(key, count+1)
		h.list = nil
	}
	h.size += added
	return added
}

func (h *hashSetData) remove(key int, count uint) int {
	var removed int
	if h.next != nil {
		removed = h.next[hash(key, count)].remove(key, count+1)
	} else {
		for i, v := range h.list {
			if v == key {
				removed = 1
			} else if removed != 0 {
				h.list[i-1] = v
			}
		}
		h.list = h.list[:h.size-removed]
	}
	h.size -= removed
	if h.size == 0 {
		h.list = nil
		h.next = nil
	}
	return removed
}

func (h *hashSetData) contains(key int, count uint) bool {
	if h.next != nil {
		return h.next[hash(key, count)].contains(key, count+1)
	}
	for _, v := range h.list {
		if v == key {
			return true
		}
	}
	return false
}