排序
——归并排序 扩展:
小和问题及逆序数问题
小和问题可以转换成每个数的贡献有多少,比如1右边有4个比他大的数,则1的贡献为1*4,在归并排序的合并过程中,每次在左数组的中遇到较小值时就计算右数组有多少个比他大的数,则是该数当前的贡献
逆序对问题可以转换成,当右边数组中遇到较小值时就计算左数组中有多少个比他大的数,则是当前逆序对数的贡献
// 小和问题
func sortArray(nums []int) int {
tmp := make([]int, len(nums))
ans := 0
var sortMerge func(i, j int)
sortMerge = func(i, j int) {
if i >= j {
return
}
mid := (i + j) / 2
sortMerge(i, mid)
sortMerge(mid+1, j)
l := i
r := mid + 1
idx := 0
for l <= mid && r <= j {
if nums[l] < nums[r] {
ans += nums[l] * (j - r + 1)
tmp[idx] = nums[l]
l++
} else {
tmp[idx] = nums[r]
r++
}
idx++
}
for l <= mid {
tmp[idx] = nums[l]
idx++
l++
}
for r <= j {
tmp[idx] = nums[r]
idx++
r++
}
for k := 0; k < j-i+1; k++ {
nums[i+k] = tmp[k]
}
}
sortMerge(0, len(nums)-1)
return ans
}
——快速排序(荷兰国旗)
func quickSort(nums []int, L int, R int) {
if L < R {
rand.Seed(time.Now().UnixNano())
t := rand.Intn(R-L+1) + L
nums[R], nums[t] = nums[t], nums[R]
p := partition(nums, L, R)
quickSort(nums, L, p[0]-1)
quickSort(nums, p[1]+1, R)
}
return
}
func partition(nums []int, L, R int) []int {
// R是标志位
less := L - 1
more := R
for L < more {
//小于区右移,小区区的第一个元素和当前L元素交换,L右移
if nums[L] < nums[R] {
less++
nums[less], nums[L] = nums[L], nums[less]
L++
//大于区左移,大于区第一个元素和当前L元素交换,下一轮比较新的L
} else if nums[L] > nums[R] {
more--
nums[more], nums[L] = nums[L], nums[more]
//相等就只右移L
} else {
L++
}
}
//交换标志位和大于区第一个元素
nums[more], nums[R] = nums[R], nums[more]
return []int{less + 1, more}
}
——堆排序
func heapSort(arr []int) []int {
if arr == nil || len(arr) < 2 {
return arr
}
for i := 0; i < len(arr); i++ { // O(N)
heapInsert(arr, i) // O(logN)
}
heapSize := len(arr) - 1
arr[0], arr[heapSize] = arr[heapSize], arr[0]
for heapSize > 0 { // O(N)
heapify(arr, 0, heapSize) //O(logN)
heapSize--
arr[0], arr[heapSize] = arr[heapSize], arr[0]
}
return arr
}
func heapInsert(arr []int, index int) {
//插入时不断和父节点比,大于就和父节点交换
for arr[index] > arr[(index-1)/2] {
arr[index], arr[(index-1)/2] = arr[(index-1)/2], arr[index]
index = (index - 1) / 2
}
}
func heapify(arr []int, index int, heapSize int) {
left := index*2 + 1
for left < heapSize {
var largest int
//在左右孩子节点中找到最大的孩子
if left+1 < heapSize && arr[left+1] > arr[left] {
largest = left + 1
} else {
largest = left
}
//父节点和最大的孩子比较
if arr[largest] < arr[index] {
largest = index
}
if largest == index {
break
}
//交换值,进行下一轮比较
arr[largest], arr[index] = arr[index], arr[largest]
index = largest
left = index*2 + 1
}
}