荷兰国旗问题(partition)总结

在之前总结的的快速排序算法中,用到了partition算法,故今天来总结下partition算法和其应用
partition算法,又称为荷兰国旗问题,其主要包括两个问题。

文章目录

  • 1 问题1-二分partition
    • 1.1 算法思想
    • 1.2 Python代码
  • 2 问题2-三分partition
    • 2.1 算法思想
    • 2.2 Python代码
  • 3 partition算法应用
    • 3.1 快速排序
    • 3.2 寻找数组第K大的数

1 问题1-二分partition

给定一个数组a和一个数n,把小于等于n的数字放在数组的左边,大于n的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(n)

1.1 算法思想

1、首先定义两个下标:
下标1:less=-1,表示<=n的区域;
下标2:p=0,表示当前值所在位置。
2、接着进行判断:
1)当前值<=划分值n(也叫基准值/枢轴),则当前数与<=区域的下一个数交换,然后<=区域扩大一位(即less+1),并且当前值指针p跳下一个
2)当前值>n,则当前值指针p直接跳下一个

1.2 Python代码

###荷兰国旗问题——问题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]

2 问题2-三分partition

给定一个数组a和一个数n,把小于n的数字放在数组的左边,等于n的数字放中间,大于n的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(n)

2.1 算法思想

1、此时可以定义三个下标:
下标1:less=-1,表示小于n的区域;
下标2:more=len(a),表示大于n的区域
下标3:p=0,表示当前位置
2、 判断:
1)当前值=n,p指针直接跳下一个
2)当之值n,则当前值与>区域的前一个数交换,>区域扩大一位(即more-1),特别注意当前指针位置不变
  *(与<区域交换后直接跳下一个不同的是,这里并不确定换过来的数与n的关系,所以要对该数进行判断)*
4)当前数与>区域撞上,则停止整个过程

2.2 Python代码

###荷兰国旗问题——问题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]

3 partition算法应用

3.1 快速排序

见之前总结的文章

3.2 寻找数组第K大的数

使用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))

你可能感兴趣的:(刷题,快排,荷兰国旗)