目录
前言:
本文的主题是分治,通过两道题目讲解,一道是数组中的第k个最大元素,一道是最小的k个数。
链接分别为:
215. 数组中的第K个最大元素 - 力扣(LeetCode)
LCR 159. 库存管理 III - 力扣(LeetCode)
题目分为三个部分讲解,一是题目解析,二是算法原理,三是算法编写,那么,话不多说,直接进行主题咯。
数组中的第K个最大元素
题目解析

题目的要求非常简单,让我们找出数组中的第K个大的元素,该题目是上篇文章中快速排序的Top K问题,所以该道题目的基础是颜色分类那道题目和数组分三块的思想。
那么直接进入算法原理部分咯。
算法原理
在前文我们知道,我们利用三个指针,将数组划分成了三个区域,分别是小于K的,等于K的,大于K的,那么我们要在该区域里面查找到第K个最大的元素,其实当我们划分好了区域之后,我们不妨分情况讨论,对于第三个区域,命中第K个数的可能性是最大的。
所以我们首先可以讨论C区域,对于讨论的前提是我们应该知道该区域有多少个元素,如果该区域的元素甚至没有K个,那么肯定就不用在这里找了,我们应该直接去找B区域,所以判断条件应该是C >= K,如果满足该条件,就直接在该区域找,这样,a和b区域的值就直接排掉了,就大大减少了时间复杂度。所以同样的,递归式的在该区域里面查找。
对于第二个区域,因为第二个区域所有的元素都是一样的,如果在该区域查找了,我们直接返回该区域的任何一个值就可以了。
对于第一个区域,也就是a,如果走到了该区域,就说明b和c两个区域都不满足条件,也就是说,k的值应该是大于b + c的,此时我们不妨将题目要求改变一下,它不是要找最大的第K个值吗,但是这个K又比较大,我们就可以将题目转换为,在a区域里面,找k - b - c的最大值,因为a区域里面的值都是小的,里面找K是行不通的,毕竟区间都变化了。
所以该题目我们甚至是可以直接使用快排的模板,然后分情况讨论即可。

算法编写
cpp
class Solution
{
public:
int GetRandom(vector<int>& v, int left, int right)
{
return v[rand() % (right - left + 1) + left];
}
int qsort(vector<int>& v, int left, int right, int k)
{
if (left >= right) return v[left];
int key = GetRandom(v, left, right);
int _left = left - 1, _right = right + 1, cur = left;
while (cur < _right)
{
if (v[cur] < key)
swap(v[++_left], v[cur++]);
else if (v[cur] == key)
cur++;
else
swap(v[--_right], v[cur]);
}
int b = _right - _left - 1, c = right - cur + 1;
if (c >= k)
return qsort(v, _right, right, k);
else if (b + c >= k)
return key;
else return qsort(v, left, _left, k - c - b);
}
int findKthLargest(vector<int>& nums, int k)
{
srand((unsigned int)time(NULL));
return qsort(nums, 0, nums.size() - 1, k);
}
};
库存管理
题目解析

题目要求也是很简单,返回最小的k个数即可,对于这种题目,一共有四种题型,分别是找最大的第K个数,找最小的第K个数,找最小的K个数,找最大的K个数。
题目的基本思路都是一样的,我们直接进入算法原理部分吧,
算法原理

其实对于这道题的解法非常多的,可以直接排序,然后返回,时间复杂度是N* LogN,也可以使用大小堆,时间复杂度是N * logK,但是都没有N来的简单。
我们使用快速选择排序算法可以实现N,基本思想还是一样的,数组分为三块,随机选择基准数即可。
那么我们主要是要讨论:

以上三种情况,对于第一种情况,如果a > k的情况,那么我们直接在里面找就可以了。如果是不满足该条件,我们就应该去第二个区间里面查找,此时因为我们已经将最小的数防在了一起,直接返回就可以了。
当以上的两种情况都不满足的话,我们就应该在第三个区间找,此时我们已经找到了a + b个元素,我们只需要找剩下的k - a - b个元素就可以了。
所以只需要将上面的题目稍加改动就可以了。
算法编写
cpp
class Solution
{
public:
int GetRandom(vector<int>& v, int left ,int right)
{
return v[rand() % (right - left + 1) + left];
}
void qsort(vector<int>& v, int left, int right, int k)
{
if(left >= right) return;
int _left = left - 1, _right = right + 1, cur = left;
int key = GetRandom(v, left, right);
while(cur < _right)
{
if(v[cur] < key) swap(v[++_left],v[cur++]);
else if(v[cur] == key) cur++;
else swap(v[--_right],v[cur]);
}
int a = _left - left + 1, b = (_right - 1) - (_left + 1) + 1;
if(a > k) qsort(v, left, _left, k);
else if(a + b >= k) return;
else qsort(v, _right, right, k - a - b);
}
vector<int> inventoryManagement(vector<int>& nums, int k)
{
srand((unsigned int)time(NULL));
qsort(nums,0, nums.size() - 1, k);
return { nums.begin(), nums.begin() + k};
}
};
感谢阅读!