leetcode快排解题心得

引言

快排问题是面试常考的基础题,leetcode 排序数组 就是一道专门练手数组排序的题目,快排的思路就在于随机选择一个数作为pivot,使得pivot左边的数都小于nums[pivot], 右边的数都大于等于nums[pivot], 代码的核心就在选择好pivot数之后,如何写代码使得左边的数都小于nums[pivot], 右边的数都大于等于nums[pivot]

初步尝试

我一开始代码如下:

def quicksort(self, nums, start, end):
    if start >= end:
    	return 
    if end - start + 1 == 2:
        if nums[end] < nums[start]:
            nums[start], nums[end] = nums[end], nums[start]
        return
    index = random.randint(start, end)
    nums[index], nums[end] = nums[end], nums[index]
    i, j = start, end-1
    while i < j:
        while nums[i] < nums[end]:
            i += 1
        nums[i], nums[j] = nums[j], nums[i]
        j -= 1
    nums[i], nums[end] = nums[end], nums[i]
    self.quicksort(nums, start, i - 1)
    self.quicksort(nums, i + 1, end)

提交自己的程序在一些case上面报错了,如这个case,[-2, -1, -1, 0, -1, 0], 并且这个case的错误是随机出现,因为pivot选择是随机的。

调试分析

经过调试发现发现我的错误在于,当index 为5, i=3 的时候,这时数组已经是[-2, -1, -1, -1, 0, 0], 按理已经排好序,但是接下来的一步nums[i], nums[end] = nums[end], nums[i] 就导致变成了[-2, -1, -1, 0, 0, -1],导致程序出错,分析研究在于目前程序能够保证 s t a r t → i − 1 start \to i-1 starti1 都是 < n u m s [ e n d ] <nums[end],同时 i + 1 → e n d − 1 i+1\to end-1 i+1end1 都是 ⩾ n u m s [ e n d ] \geqslant nums[end] nums[end],但是 n u m s [ i ] 和 n u m s [ e n d ] nums[i] 和 nums[end] nums[i]nums[end]之间的关系却不清楚,所以我加了一个判断具体如下:

def quicksort(self, nums, start, end):
    if start >= end:
    	return 
    if end - start + 1 == 2:
        if nums[end] < nums[start]:
            nums[start], nums[end] = nums[end], nums[start]
        return
    index = random.randint(start, end)
    nums[index], nums[end] = nums[end], nums[index]
    i, j = start, end-1
    while i < j:
        while nums[i] < nums[end]:
            i += 1
        nums[i], nums[j] = nums[j], nums[i]
        j -= 1
    if nums[end] <= nums[i]:
    	nums[i], nums[end] = nums[end], nums[i]
    	self.quicksort(nums, start, i - 1)
    	self.quicksort(nums, i + 1, end)
    else:
    	nums[i+1], nums[end] = nums[end], nums[i+1]
    	self.quicksort(nums, start, i)
    	self.quicksort(nums, i+2, end)

对比分析

虽然程序通过了平台的测试,但是自己的代码逻辑实在不elegant,和印象中快排不一样,为此自己对比的了leetcode官方题解,具体如下:

def randomized_partition(self, nums, l, r):
    pivot = random.randint(l, r)
    nums[pivot], nums[r] = nums[r], nums[pivot]
    i = l - 1
    for j in range(l, r):
        if nums[j] < nums[r]:
            i += 1
            nums[j], nums[i] = nums[i], nums[j]
    i += 1
    nums[i], nums[r] = nums[r], nums[i]
    return i

和自己的题解一对比,官网的题解非常的清晰,妙在定义了一个变量 i i i来记录当前所有小于 n u m s [ r ] nums[r] nums[r]的最大索引,并且要在 l − 1 l-1 l1开始,因为你不一直到 n u m s [ l ] 与 n u m s [ r ] nums[l] 与nums[r] nums[l]nums[r]的大小关系,最后不要忘了 i + = 1 i+=1 i+=1 作为新的和 n u m s [ r ] nums[r] nums[r] 交换的索引。

结语

快排是一道非常经典的排序题,但是面试时拿起笔写的时候却一时没有思路,其核心思路是将待排序序列分成前后两个序列,保证前的序列的数都大于后面的序列,在分别递归地对前后两个序列进行快排操作,从而实现最终的排序。在寻找pivot的时候,先随机一个index,然后设置一个变量,记录当前小于随机出来的数的最大索引,每找到一个新的小于当前随机pivot的数,该变量就加1,最后介绍循环后该变量还要继续加1,并交换两个索引指向的数,从而实现将待排序序列分成前后两个序列。

你可能感兴趣的:(leetcode,算法,职场和发展)