From f4af3e14e071da2c22d50fe364c3fe460e8edc39 Mon Sep 17 00:00:00 2001 From: fengzw Date: Fri, 25 Jun 2021 00:02:44 +0800 Subject: [PATCH] add: median of medians algorithm solution for Miscellaneous --- Miscellaneous/median-of-medians.go | 71 +++++++++++++++++++++++++ Miscellaneous/median-of-medians_test.go | 27 ++++++++++ 2 files changed, 98 insertions(+) create mode 100644 Miscellaneous/median-of-medians.go create mode 100644 Miscellaneous/median-of-medians_test.go diff --git a/Miscellaneous/median-of-medians.go b/Miscellaneous/median-of-medians.go new file mode 100644 index 0000000..a87e2b8 --- /dev/null +++ b/Miscellaneous/median-of-medians.go @@ -0,0 +1,71 @@ +package Miscellaneous + +import ( + "sort" +) + +// +// coverage time complexity: O(n), worst O(n) +// space complexity: O(n) +// +func findKthSmallestNumberUsingMedianOfMedians(nums []int, k int) int { + if k > len(nums) { + return -1 + } + return findPivotRecursive(nums, k, 0, len(nums)-1) +} + +func findPivotRecursive(nums []int, k, start, end int) int { + p := partitionMom(nums, start, end) + if p == k-1 { + return nums[p] + } + if p > k-1 { + return findPivotRecursive(nums, k, start, p-1) + } + return findPivotRecursive(nums, k, p+1, end) +} + +func partitionMom(nums []int, low, high int) int { + if low == high { + return low + } + + median := medianOfMedians(nums, low, high) + // median as pivot + // swap high and median + for i := low; i < high; i++ { + if nums[i] == median { + nums[i], nums[high] = nums[high], nums[i] + break + } + } + + pivot := nums[high] + i := low - 1 + for j := low; j < high; j++ { + if nums[j] < pivot { + i++ + nums[i], nums[j] = nums[j], nums[i] + } + } + nums[i+1], nums[high] = nums[high], nums[i+1] + return i + 1 +} + +func medianOfMedians(nums []int, low, high int) int { + n := high - low + 1 + if n < 5 { + return nums[low] + } + + numOfPartitions := n / 5 + medians := make([]int, numOfPartitions) + for i := 0; i < numOfPartitions; i++ { + partStart := low + i*5 + sort.Ints(nums[partStart : partStart+5]) + medians[i] = nums[partStart+2] + } + + return partitionMom(medians, 0, numOfPartitions-1) +} diff --git a/Miscellaneous/median-of-medians_test.go b/Miscellaneous/median-of-medians_test.go new file mode 100644 index 0000000..e589f92 --- /dev/null +++ b/Miscellaneous/median-of-medians_test.go @@ -0,0 +1,27 @@ +package Miscellaneous + +import "testing" + +func Test_findKthSmallestNumberUsingMedianOfMedians(t *testing.T) { + type args struct { + nums []int + k int + } + tests := []struct { + name string + args args + want int + }{ + {"case1", args{[]int{1, 5, 12, 2, 11, 5}, 3}, 5}, + {"case2", args{[]int{1, 5, 12, 2, 11, 5}, 4}, 5}, + {"case3", args{[]int{5, 12, 11, -1, 12}, 3}, 11}, + {"case4", args{[]int{5, 12, 11, -1, 12}, 6}, -1}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := findKthSmallestNumberUsingMedianOfMedians(tt.args.nums, tt.args.k); got != tt.want { + t.Errorf("findKthSmallestNumberUsingMedianOfMedians() = %v, want %v", got, tt.want) + } + }) + } +}