在之前总结的的快速排序算法中,用到了partition算法,故今天来总结下partition算法和其应用
partition算法,又称为荷兰国旗问题,其主要包括两个问题。
给定一个数组a和一个数n,把小于等于n的数字放在数组的左边,大于n的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(n)
1、首先定义两个下标:
下标1:less=-1,表示<=n的区域;
下标2:p=0,表示当前值所在位置。
2、接着进行判断:
1)当前值<=划分值n(也叫基准值/枢轴),则当前数与<=区域的下一个数交换,然后<=区域扩大一位(即less+1),并且当前值指针p跳下一个
2)当前值>n,则当前值指针p直接跳下一个
###荷兰国旗问题——问题1
def partition_Q1(arr,n):
less = -1
p = 0
while p < len(arr):
if arr[p] <= n:
arr[less+1],arr[p] = arr[p],arr[less+1]
less += 1
p += 1
else:
p += 1
return arr
测试用例1:partition_Q1([5,3,2,5,68,1,2],4)
输出:[3, 2, 1, 2, 68, 5, 5]]
测试用例2:partition_Q1([4,5,545,4,5],3)
输出:[4, 5, 545, 4, 5]
给定一个数组a和一个数n,把小于n的数字放在数组的左边,等于n的数字放中间,大于n的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(n)
1、此时可以定义三个下标:
下标1:less=-1,表示小于n的区域;
下标2:more=len(a),表示大于n的区域
下标3:p=0,表示当前位置
2、 判断:
1)当前值=n,p指针直接跳下一个
2)当之值n,则当前值与>区域的前一个数交换,>区域扩大一位(即more-1),特别注意当前指针位置不变
*(与<区域交换后直接跳下一个不同的是,这里并不确定换过来的数与n的关系,所以要对该数进行判断)*
4)当前数与>区域撞上,则停止整个过程
###荷兰国旗问题——问题2
def partition_Q2(arr,n):
less = -1
more = len(arr)
p = 0
while p < more:
if arr[p] < n:
arr[p],arr[less+1] = arr[less+1],arr[p]
less += 1
p += 1
elif arr[p] == n:
p += 1
else:
arr[p],arr[more-1] = arr[more-1],arr[p]
more -= 1
return arr
测试用例1:partition_Q2([5,3,2,5,68,1,2],3)
输出:[2, 2, 1, 3, 68, 5, 5]
测试用例2:partition_Q2([4,5,545,4,5],3)
输出:[5, 545, 4, 5, 4]
见之前总结的文章
使用partition算法将数组分为大于首元素的部分,等于首元素的部分和小于首元素的部分,然后判断k在那哪个部分中,递归的进行partition
代码实现
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
if not nums:
return
#parition分为三部分
l = [i for i in nums if i > nums[0]]
m = [i for i in nums if i == nums[0]]
r = [i for i in nums if i < nums[0]]
#判断k的位置
if k <= len(l):
return self.findKthLargest(l,k)
elif k <= len(l) + len(m):
return nums[0]
else:
return self.findKthLargest(r,k-len(l)-len(m))