排序算法模板(快速排序、归并排序)
记录一下现在学过的算法模板,免得后面又忘了然后找不到……
Quick Sort 快速排序
题目: Sort Colors
class Solution:
"""
@param nums: A list of integer which is 0, 1 or 2
@return: nothing
"""
def sortColors(self, nums):
# write your code here
if not nums:
return None
return self.quicksort(nums, 0, len(nums) - 1)
def quicksort(self, nums, start, end):
if start >= end:
return
left, right = start, end
pivot = nums[(start + end) // 2]
while left <= right:
while left <= right and nums[left] < pivot:
left += 1
while left <= right and nums[right] > pivot:
right -= 1
if left <= right:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right -= 1
self.quicksort(nums, start, right)
self.quicksort(nums, left, end)
助教的QS模板:
def quickSort(self, A, start, end):
if start >= end:
return
left, right = start, end
pivot = A[(start + end) // 2];
while left <= right:
while left <= right and A[left] < pivot:
left += 1
while left <= right and A[right] > pivot:
right -= 1
if left <= right:
A[left], A[right] = A[right], A[left]
left += 1
right -= 1
self.quickSort(A, start, right)
self.quickSort(A, left, end)
Merge Sort 归并排序
题目:Sort Integers
class Solution:
"""
@param A: an integer array
@return: nothing
"""
def sortIntegers2(self, A):
temp = [0] * len(A)
self.merge_sort(A, 0, len(A) - 1, temp)
def merge_sort(self, A, start, end, temp):
if start >= end:
return
left, right = start, end
mid = (start + end) // 2
self.merge_sort(A, start, mid, temp)
self.merge_sort(A, mid + 1, end, temp)
self.merge(A, start, mid, end, temp)
def merge(self, A, start, mid, end, temp):
left, right = start, mid + 1
index = start
while left <= mid and right <= end:
if A[left] < A[right]:
temp[index] = A[left]
index += 1
left += 1
else:
temp[index] = A[right]
index += 1
right += 1
while left <= mid:
temp[index] = A[left]
index += 1
left += 1
while right <= end:
temp[index] = A[right]
index += 1
right += 1
for i in range(start, end + 1, 1):
A[i] = temp[i]
Quick Select 快速选择
题目: Kth Largest Element
Quick Select本质还是Quick Sort,只是它根据位置关系有选择地对一部分数组进行排序。
这道题用两种方式做,第一种是排序从小到大,第二种是排序从大到小。注意观察条件的细微差别~
老师笔记:
快速选择算法的 Partition 的实质:
快速选择/快速排序中的 partition 是 可左可右 的partition,也就是说,对于nums[i] == pivot 时,这个数字既可以放在左边,也可以放在右边。
为什么这样划分数组呢?
原因是为了避免出现类似 [1,1,1,1,1,1] 的数组中的元素,全部被分到一边的情况。我们让 nums[i] == pivot 的情况既不属于左边也不属于右边,这样就能够让 partition 之后的结果稍微平衡一些。 如果 quick select / quick sort 写成了nums[i] < pivot 在左侧,nums[i] >= pivot 在右侧这种形式,就会导致划分不平均,从而导致错误或者超时。
为什么问题《partition array》不能使用同样的代码?
对于问题《partition array》来说,题目的要求是将数组划分为两个部分,一部分满足一个条件,另外一部分不满足这个条件,所以可以严格的把 nums[i] < pivot 放在左侧,把 nums[i] >= pivot 放在右侧,这样子做完一次 partition 之后,就能够将这两部分分开。
总结
简单的说就是,quick select 和 quick sort 的 partition 目标不是将数组严格的按照 nums[i] < pivot 和nums[i] >= pivot 去拆分开,而是只要能够让左半部分 <= 右半部分即可。这样子 nums[i] == pivot 放在哪儿都无所谓,两边都可以放。
(1)排序从小到大
class Solution:
# @param k & A a integer and an array
# @return ans a integer
def kthLargestElement(self, k, A):
if not A or k < 1 or k > len(A):
return None
return self.partition(A, 0, len(A) - 1, len(A) - k)
def partition(self, nums, start, end, k):
"""
During the process, it's guaranteed start <= k <= end
"""
if start == end:
return nums[k]
left, right = start, end
pivot = nums[(start + end) // 2]
while left <= right:
while left <= right and nums[left] < pivot:
left += 1
while left <= right and nums[right] > pivot:
right -= 1
if left <= right:
nums[left], nums[right] = nums[right], nums[left]
left, right = left + 1, right - 1
# left is not bigger than right
if k <= right:
return self.partition(nums, start, right, k)
if k >= left:
return self.partition(nums, left, end, k)
return nums[k]
(2)排序从大到小(折腾了好久……突然某一次改对了 迷幻)
class Solution:
"""
@param n: An integer
@param nums: An array
@return: the Kth largest element
"""
def kthLargestElement(self, k, A):
# write your code here
if not A or k < 1 or k > len(A):
return None
return self.partition(A, 0, len(A) - 1, k) #这里输入的k应该指的是index!所以如果是从大到小,输入的应该是k - 1比较容易想
def partition(self, nums, start, end, k):
"""
During the process, it's guaranteed start <= k <= end
"""
if start == end:
return nums[start] # 也可以是nums[k]如果主函数中输入的是k-1
left, right = start, end
pivot = nums[(start + end) // 2]
while left <= right:
while left <= right and nums[left] > pivot:
left += 1
while left <= right and nums[right] < pivot:
right -= 1
if left <= right:
nums[left], nums[right] = nums[right], nums[left]
left, right = left + 1, right - 1
# left is not bigger than right
if start + k - 1 <= right: # if k <= right
return self.partition(nums, start, right, k)
if start + k - 1 >= left: # k <= left
return self.partition(nums, left, end, k - (left - start)) # k
return nums[right + 1] # nums[k]