刷题使我快乐,满脸开心.jpg

  • 来源:力扣(LeetCode)
  • 链接:https://leetcode.cn/problems/sort-an-array/
  • 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目

给你一个整数数组 nums,请你将该数组升序排列。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

示例 2:

输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]

提示:

  • 1 <= nums.length <= 5 * 104
  • -5 * 104 <= nums[i] <= 5 * 104

思路

注意快排时候测试用例有坑,会有一个茫茫多一样数字的用例,导致常规快排超时
可以用增加交换频率 + 随机选择中间点的方式增加应对此类情况的效率
唔,堆排赛高?

代码

func sortArray(nums []int) []int {
	return quickSort(nums, 0, len(nums)-1)
    // return heapSort(nums)
}

func quickSort(nums []int, left, right int) []int {
	if left > right {
		return nil
	}
	i, j, pivot := left, right, rand.Intn(right-left+1)+left
	// 随机选点并增加交换频率写法,则需要在开始就进行交换,这样可以让中值位置经常移动,便于左右开弓遍历
	nums[i], nums[pivot] = nums[pivot], nums[i]
	for i < j {
		// 1、拆解常规的的严格大于才交换的条件(nums[j] >= nums[i]),增加交换频率
		for i < j && nums[j] > nums[i] {
			j--
		}
		if i < j {
			nums[i], nums[j] = nums[j], nums[i]
			i++
		}
		// 2、并且让左右交替进行。两者共同作用,这样就可以让数据基本一致时,最终选取的点可以停留在数组中间位置附近
		for i < j && nums[i] < nums[j] {
			i++
		}
		if i < j {
			nums[i], nums[j] = nums[j], nums[i]
			j--
		}
	}
	// 常规写法,中值位置不动,只在左右寻找时交换i、j位置,可以交替完后将中值移动到中间即可
	// nums[i], nums[left] = nums[left], nums[i]
	quickSort(nums, left, i-1)
	quickSort(nums, i+1, right)
	return nums
}

func heapSort(nums []int) []int {
	end := len(nums) - 1
	for i := end / 2; i >= 0; i-- {
		heapify(nums, i, end)
	}
	for i := end; i >= 0; i-- {
		nums[0], nums[i] = nums[i], nums[0]
		heapify(nums, 0, i-1)
	}
	return nums
}

func heapify(nums []int, root, end int) {
	left, right, largest := 2*root+1, 2*root+2, root
	if left <= end && nums[left] > nums[largest] {
		largest = left
	}
	if right <= end && nums[right] > nums[largest] {
		largest = right
	}
	if largest != root {
		nums[root], nums[largest] = nums[largest], nums[root]
		heapify(nums, largest, end)
	}
}