From 5623eef26687bd183bbd717a5d9fe3b9bafe9610 Mon Sep 17 00:00:00 2001 From: rihib Date: Sat, 17 Aug 2024 16:32:30 +0900 Subject: [PATCH 1/2] pullrequests/top_k_frequent_elements --- pullrequests/top_k_frequent_elements/step1.go | 6 ++++++ pullrequests/top_k_frequent_elements/step2.go | 6 ++++++ pullrequests/top_k_frequent_elements/step3.go | 6 ++++++ 3 files changed, 18 insertions(+) create mode 100644 pullrequests/top_k_frequent_elements/step1.go create mode 100644 pullrequests/top_k_frequent_elements/step2.go create mode 100644 pullrequests/top_k_frequent_elements/step3.go diff --git a/pullrequests/top_k_frequent_elements/step1.go b/pullrequests/top_k_frequent_elements/step1.go new file mode 100644 index 0000000..b0c1012 --- /dev/null +++ b/pullrequests/top_k_frequent_elements/step1.go @@ -0,0 +1,6 @@ +//lint:file-ignore U1000 Ignore all unused code +package template + +/* +COMMENT +*/ diff --git a/pullrequests/top_k_frequent_elements/step2.go b/pullrequests/top_k_frequent_elements/step2.go new file mode 100644 index 0000000..b0c1012 --- /dev/null +++ b/pullrequests/top_k_frequent_elements/step2.go @@ -0,0 +1,6 @@ +//lint:file-ignore U1000 Ignore all unused code +package template + +/* +COMMENT +*/ diff --git a/pullrequests/top_k_frequent_elements/step3.go b/pullrequests/top_k_frequent_elements/step3.go new file mode 100644 index 0000000..b0c1012 --- /dev/null +++ b/pullrequests/top_k_frequent_elements/step3.go @@ -0,0 +1,6 @@ +//lint:file-ignore U1000 Ignore all unused code +package template + +/* +COMMENT +*/ From 51a688c6e191357db8bad5da74560d68cbd2fb20 Mon Sep 17 00:00:00 2001 From: rihib Date: Sat, 17 Aug 2024 20:36:36 +0900 Subject: [PATCH 2/2] pullrequests/top_k_frequent_elements --- pullrequests/top_k_frequent_elements/step1.go | 26 ++- pullrequests/top_k_frequent_elements/step2.go | 19 +- pullrequests/top_k_frequent_elements/step3.go | 188 +++++++++++++++++- 3 files changed, 227 insertions(+), 6 deletions(-) diff --git a/pullrequests/top_k_frequent_elements/step1.go b/pullrequests/top_k_frequent_elements/step1.go index b0c1012..a3951af 100644 --- a/pullrequests/top_k_frequent_elements/step1.go +++ b/pullrequests/top_k_frequent_elements/step1.go @@ -1,6 +1,28 @@ //lint:file-ignore U1000 Ignore all unused code -package template +package topkfrequentelements /* -COMMENT +時間:13分 +とりあえずO(n)で解けそうだったので解いてみました。 +(あとで他の人のPRを読んでこれがバケットソートと呼ばれているものだと知りました、、) */ +func topKFrequentStep1(nums []int, k int) []int { + freq := make(map[int]int) + for _, n := range nums { + freq[n]++ + } + + cs := make([][]int, len(nums)) + for n, c := range freq { + cs[c-1] = append(cs[c-1], n) + } + + var res []int + for i := len(cs) - 1; i >= 0; i-- { + res = append(res, cs[i]...) + if len(res) >= k { + break + } + } + return res +} diff --git a/pullrequests/top_k_frequent_elements/step2.go b/pullrequests/top_k_frequent_elements/step2.go index b0c1012..22e8c4a 100644 --- a/pullrequests/top_k_frequent_elements/step2.go +++ b/pullrequests/top_k_frequent_elements/step2.go @@ -1,6 +1,21 @@ //lint:file-ignore U1000 Ignore all unused code -package template +package topkfrequentelements /* -COMMENT +Step1の変数名などをより明確になるように変更しました。 */ +func topKFrequentStep2(nums []int, k int) []int { + frequency := make(map[int]int) + for _, num := range nums { + frequency[num]++ + } + countToNum := make([][]int, len(nums)+1) + for num, count := range frequency { + countToNum[count] = append(countToNum[count], num) + } + topK := make([]int, 0, k) + for i := len(countToNum) - 1; i >= 0 && len(topK) < k; i-- { + topK = append(topK, countToNum[i]...) + } + return topK +} diff --git a/pullrequests/top_k_frequent_elements/step3.go b/pullrequests/top_k_frequent_elements/step3.go index b0c1012..0159d88 100644 --- a/pullrequests/top_k_frequent_elements/step3.go +++ b/pullrequests/top_k_frequent_elements/step3.go @@ -1,6 +1,190 @@ //lint:file-ignore U1000 Ignore all unused code -package template +package topkfrequentelements + +import ( + "container/heap" + "math/rand/v2" + "sort" +) /* -COMMENT +他の人のPRを見て、他の解法も実装してみました。 +クイックセレクトはピボットの選択としてランダムなものと中央値を用いるものの両方を実装しました(中央値の中央値はやらなくても良いかなと思い飛ばしました)。 */ +type Element struct { + num int + count int +} + +func topKFrequentBucketSort(nums []int, k int) []int { + frequency := make(map[int]int) + for _, num := range nums { + frequency[num]++ + } + countToNum := make([][]int, len(nums)+1) + for num, count := range frequency { + countToNum[count] = append(countToNum[count], num) + } + topK := make([]int, 0, k) + for i := len(countToNum) - 1; i >= 0 && len(topK) < k; i-- { + topK = append(topK, countToNum[i]...) + } + return topK +} + +func topKFrequentQuickselect(nums []int, k int) []int { + frequency := make(map[int]int) + for _, num := range nums { + frequency[num]++ + } + elements := make([]Element, 0, len(frequency)) + for num, count := range frequency { + elements = append(elements, Element{num: num, count: count}) + } + quickselect(elements, 0, len(elements)-1, len(elements)-k, partitionRandom) + topK := make([]int, k) + for i := 0; i < k; i++ { + topK[i] = elements[len(elements)-1-i].num + } + return topK +} + +func quickselect( + elements []Element, left, right, k int, + partition func([]Element, int, int) int) { + for left < right { + pivotIndex := partition(elements, left, right) + if pivotIndex == k { + return + } + if pivotIndex < k { + left = pivotIndex + 1 + } else { + right = pivotIndex - 1 + } + } +} + +func partitionRandom(elements []Element, left, right int) int { + pivotIndex := left + rand.IntN(right-left+1) + elements[pivotIndex], elements[right] = elements[right], elements[pivotIndex] + pivot := elements[right].count + storeIndex := left + for i := left; i < right; i++ { + if elements[i].count < pivot { + elements[i], elements[storeIndex] = elements[storeIndex], elements[i] + storeIndex++ + } + } + elements[storeIndex], elements[right] = elements[right], elements[storeIndex] + return storeIndex +} + +func partitionMedianOf3(elements []Element, left, right int) int { + mid := left + (right-left)/2 + if elements[right].count < elements[left].count { + elements[right], elements[left] = elements[left], elements[right] + } + if elements[mid].count < elements[left].count { + elements[mid], elements[left] = elements[left], elements[mid] + } + if elements[right].count < elements[mid].count { + elements[right], elements[mid] = elements[mid], elements[right] + } + pivotIndex := mid + elements[pivotIndex], elements[right] = elements[right], elements[pivotIndex] + pivot := elements[right].count + storeIndex := left + for i := left; i < right; i++ { + if elements[i].count < pivot { + elements[i], elements[storeIndex] = elements[storeIndex], elements[i] + storeIndex++ + } + } + elements[storeIndex], elements[right] = elements[right], elements[storeIndex] + return storeIndex +} + +func topKFrequentPDQSort(nums []int, k int) []int { + frequency := make(map[int]int) + for _, num := range nums { + frequency[num]++ + } + numsSet := make([]int, 0, len(frequency)) + for num := range frequency { + numsSet = append(numsSet, num) + } + sort.Slice(numsSet, func(i, j int) bool { + return frequency[numsSet[i]] > frequency[numsSet[j]] + }) + return numsSet[:k] +} + +func topKFrequentMinHeap(nums []int, k int) []int { + frequency := make(map[int]int) + for _, num := range nums { + frequency[num]++ + } + h := &MinHeap{} + heap.Init(h) + for num, count := range frequency { + heap.Push(h, Element{num: num, count: count}) + if h.Len() > k { + heap.Pop(h) + } + } + topK := make([]int, 0, k) + for h.Len() > 0 { + topK = append(topK, heap.Pop(h).(Element).num) + } + return topK +} + +type MinHeap []Element + +func (h *MinHeap) Push(x interface{}) { + *h = append(*h, x.(Element)) +} + +func (h *MinHeap) Pop() interface{} { + x := (*h)[len(*h)-1] + *h = (*h)[0 : len(*h)-1] + return x +} + +func (h MinHeap) Len() int { return len(h) } +func (h MinHeap) Less(i, j int) bool { return h[i].count < h[j].count } +func (h MinHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } + +func topKFrequentMaxHeap(nums []int, k int) []int { + frequency := make(map[int]int) + for _, num := range nums { + frequency[num]++ + } + h := &MaxHeap{} + heap.Init(h) + for num, count := range frequency { + heap.Push(h, Element{num: num, count: count}) + } + topK := make([]int, 0, k) + for i := 0; i < k; i++ { + topK = append(topK, heap.Pop(h).(Element).num) + } + return topK +} + +type MaxHeap []Element + +func (h *MaxHeap) Push(x interface{}) { + *h = append(*h, x.(Element)) +} + +func (h *MaxHeap) Pop() interface{} { + x := (*h)[len(*h)-1] + *h = (*h)[0 : len(*h)-1] + return x +} + +func (h MaxHeap) Len() int { return len(h) } +func (h MaxHeap) Less(i, j int) bool { return h[i].count > h[j].count } +func (h MaxHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }