目录
- 颜色分类
- 题目解析
- 算法原理
- 代码
- 排序数组
- 题目解析
- 算法原理
- 代码
- 数组中第K个最大元素
- 题目解析
- 算法原理
- 代码
- LCR 159. 库存管理 III
- 题目解析
- 算法原理
- 代码
颜色分类
题目链接
题目解析
数组分为三块
算法原理
1.如果nums[i] == 0,++left, i++下标对应元素交换,先++left后元素对应是1,和0元素交换,再i++
2.如果nums[i] == 2,- -right,i下标对应元素交换,先- -right,对应元素是未知的未扫描的,和2交换,i下标对应元素是未知的,不能++还要进行下一次的判断
3.如果nums[i] == 1,直接++i,因为i下标的左边都是1,++后左边还都是1
代码
class Solution
{
public:
void sortColors(vector<int>& nums)
{
// 三指针,数组分成三块
int left = -1,i = 0,right = nums.size();
// i == right结束循环
// 0 1 2 left边缘到右边 right边缘到左边
while(i < right)
{
if(nums[i] == 0)
swap(nums[++left],nums[i++]);
else if(nums[i] == 1)
i++;
else
swap(nums[--right],nums[i]);
}
}
};
排序数组
排序数组题目链接
题目解析
排成一个升序的数组
算法原理
随机选数和三路划分
1.三路划分:选出==key,<key,>key的,按照颜色分类那题一样的做法
2.随机选数:选数的范围是在[left,right]中的一个随机值,每一次排序选一个随机数
r = rand() nums[r % (right - left + 1) + left]
再加一个left是因为偏移量,让它能够在[left,right]区间中
[0,n-1-left] -> [left,n-1 ]-> [left,right]
代码
class Solution
{
public:
int func(vector<int>& nums,int l,int r)
{
int k = rand();
// 保证选数在[l,r]之间
return nums[k % (r - l + 1) + l];
}
void qsort(vector<int>& nums,int l,int r)
{
// 有空数组和1个数的数组的情况
if(l >= r)
return;
// 选数
int key = func(nums,l,r);
int i = l,left = l-1,right = r + 1;
// 排序
while(i < right)
{
if(nums[i] < key) swap(nums[++left],nums[i++]);
else if(nums[i] == key) i++;
else swap(nums[--right],nums[i]);
}
// 递归
// [l,left] [left + 1,right - 1] [right,r]
qsort(nums,l,left);
qsort(nums,right,r);
}
vector<int> sortArray(vector<int>& nums)
{
srand(time(NULL));// 设置随机数的种子
// 数组分成三份 优化随机选数
qsort(nums,0,nums.size()-1);
return nums;
}
};
数组中第K个最大元素
题目解析
算法原理
1.可以用堆排序找第K大的元素
2.还可以用快排的选择
快排的选择跟上一题的逻辑很像
第K大的元素一定落在第一次数组分成三份的某一个区间内,所以只要去其中一个区间用快排可以解决,要注意的是第三种情况,传k时要传k-b-c,a,b,c都表示区间中元素的个数,k-b-c表示在第一个区间内找第K大的
第一种情况在c中找第K大的
第二种第K大的落在里面就是key了
代码
class Solution
{
public:
// 把数组分成三份
int Selectnums(vector<int>& nums,int left,int right)
{
// 随机选数
int r = rand();
return nums[r % (right - left + 1) + left];
}
int qsort(vector<int>& nums,int left,int right,int k)
{
//返回条件
// 只有一个元素
// 没有空数组的情况因为要找第K大的数,至少要有一个数,有一个数的数组
if(left == right)
return nums[left];
int key = Selectnums(nums,left,right);
int i = left,l = left - 1,r = right + 1;
while(i < r)
{
if(key == nums[i]) i++;
else if(key > nums[i]) swap(nums[++l],nums[i++]);
else swap(nums[--r],nums[i]);
}
// 递归
// [left,l] [l+1,r-1] [r,right]
// [0,l++] [r--,n-1]
int a = l - left + 1;
int b = r - l - 1;
int c = right - r + 1;
if(c >= k)
return qsort(nums,r,right,k);
else if((b+c) >= k)
return key;
else
return qsort(nums,left,l,k - b - c);
}
int findKthLargest(vector<int>& nums, int k)
{
// 随机选数
srand(time(NULL));
int n = nums.size();
return qsort(nums,0,n-1,k);
}
};
LCR 159. 库存管理 III
题目链接
题目解析
以任意顺序返回题目中的K个最小元素
算法原理
快速选择算法和上一题类似
- a个 > k个,在[l,left]区域排序最小的k个元素
- a + b个 >= k个,在[l,right]区域中,直接返回key,因为key左边(包括key)一定是排好大小的,所以返回
- 前二种情况都不满足,在[right,r]区域中找k-a-b个最小的元素
- a == k的情况,肯定排好了,直接返回,因为<=key这变都是有序的
- [2,5,7,4] -> 2作为key [2,4,5,7]是排好后的
[2,4,5,7]这种a > k还要排序,k在key的后面
[2,5,7,4] -> 5作为key [2,4,5,7]是排好后的
key 左边都是有序的
代码
class Solution
{
public:
// 随机选数
int GetRound(vector<int>& nums,int left,int right,int k)
{
int r = rand();
return nums[r % (right - left + 1) + left];
}
vector<int> inventoryManagement(vector<int>& stock, int cnt)
{
srand(time(NULL));
qsort(stock,0,stock.size()-1,cnt);
return {stock.begin(),stock.begin()+cnt};
// int n = stock.size();
// sort(stock.begin(),stock.end());
// vector<int> ret;
// int i = 0;
// while(cnt--)
// {
// ret.push_back(stock[i++]);
// }
// return ret;
}
void qsort(vector<int>& nums,int l,int r,int k)
{
if(l >= r) return;
int key = GetRound(nums,l,r,k);
int i = l,left = l - 1,right = r + 1;
while(i < right)
{
if(key > nums[i]) swap(nums[++left],nums[i++]);
else if(key == nums[i]) i++;
else swap(nums[--right],nums[i]);
}
// [l,left] [left + 1,right - 1] [right,r]
int a = left - l + 1,b = right - left - 1,c = r - right + 1;
if(a > k) qsort(nums,l,left,k);
else if(a + b >= k) return;
else qsort(nums,right,r,k - a - b);
}
};