leetcode 归并、快排、堆排序整理

排序
——归并排序 扩展:
小和问题及逆序数问题
在这里插入图片描述
小和问题可以转换成每个数的贡献有多少,比如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
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值