Partition算法_求第K大元素

1.二分Partition

二分Partition算法是指在O(n)的时间复杂度和O(1)的空间复杂度的情况下将一个数组分为大于某个数和小于某个数的两部分。快速排序其实就是分治+Partition算法。

int partition(vector<int> &nums, int begin, int end)
{
    int pivot = nums[begin];
    int pos = begin;
    for(int i = begin+1; i < end; ++i)
    {
        if(nums[i] <= pivot)
            swap(nums[++pos],nums[i]);
    }
    swap(nums[pos], nums[begin]);
    return pos;
}

在cpp的stl中的算法库提供了这个算法的api:

std::nth_element(container, begin, end);




2.第K大的数

通过最基本的Partition算法,我们可以引用于求数组的第K大的数,比如中位数。我们只需要不断分成两部分,然后将多的那部分继续分成两部分。直到两边一样多。

int findKthLargest(vector<int> &nums, int k)
        {
            int len = nums.size();
            int res = 0;
            int left = 0;
            int right = len;
            while(left < right)
            {
                int pos = partition(nums, left, right);
                if(pos == len-k)
                {
                    res = nums[pos];
                    break;
                }
                else if(pos < len-k)
                    left = pos+1;
                else
                    right = pos;
            }
            return res;
        }




3.三分Partition

有的时候数组中大小关系并不只是大于和小于,还有等于。所以如果我们想将一个数组划分为小于x,等于x,大于x的三部分。那么我们可以对二分Partition进行简单的改造就可以实现上面的需求了。

int partition(vector<int> &nums, int begin, int end)
{
    int pivot = nums[begin];
    int pos1 = begin, pos2 = end;
    for (int i = begin + 1; i <= pos2; ++i)
    {
        if (nums[i] < pivot)
            swap(nums[pos1++], nums[i]);
        else if (nums[i] > pivot)
            swap(nums[pos2--], nums[i--]);
    }
    return pos1;
}

当然也可以使用二分Partition+三向切分来解决(荷兰国旗问题), 三向切分的作用就是根据目标值分为大于,等于,小于三个部分。

void wiggleSort(vector<int>& nums) 
{
	int n = nums.size();
	std::nth_element(nums.begin(), nums.begin() + n/2, nums.end());
	int mid = nums[n/2];
	
	// 3-way-partion
	int i = 0, j = 0, k = n - 1;
	while (j <= k) {
		if (nums[j] > mid) {
			swap(nums[i++], nums[j++]);
		} else if (num[j] < mid) {
			swap(nums[j], nums[k--]);
		} else {
			++j;
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值