目录
1、颜色分类
给定一个包含红色、白色和蓝色、共
n
个元素的数组nums
,**原地**对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。我们使用整数
0
、1
和2
分别表示红色、白色和蓝色。必须在不使用库内置的 sort 函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0] 输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1] 输出:[0,1,2]
class Solution {
public:
void sortColors(vector<int>& nums) {
int key=1,i=0,left=-1,right=nums.size();
while(i<right)
{
if(nums[i]<key) swap(nums[++left],nums[i++]);
else if(nums[i]==key) i++;
else swap(nums[--right],nums[i]);
}
}
};
2、快速排序
给你一个整数数组
nums
,请你将该数组升序排列。你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为
O(nlog(n))
,并且空间复杂度尽可能小。示例 1:
输入:nums = [5,2,3,1] 输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0] 输出:[0,0,1,1,2,5]
class Solution {
public:
vector<int> tmp;//定义全局的辅助数组帮组归并排序
vector<int> sortArray(vector<int>& nums) {
tmp.resize(nums.size());
mergesort(nums,0,nums.size()-1);
return nums;
}
void mergesort(vector<int>& nums,int left,int right)
{
//递归结束条件
if(left>=right) return;
//选择中间开始递归 [left,mid] [mid+1,right]
int mid=left+(right-left)/2;
mergesort(nums,left,mid);
mergesort(nums,mid+1,right);
//归并排序主逻辑
int cur1=left,cur2=mid+1,i=0;
while(cur1<=mid&&cur2<=right)
{
if(nums[cur1]<nums[cur2]) tmp[i++]=nums[cur1++];
else tmp[i++]=nums[cur2++];
}
//解决没有排序的数据
while(cur1<=mid) tmp[i++]=nums[cur1++];
while(cur2<=right) tmp[i++]=nums[cur2++];
//将辅助数组的数据拷贝到原数组
for(int i=left;i<=right;i++)
nums[i]=tmp[i-left];
}
};
3、数组中的第K个最大元素
给定整数数组
nums
和整数k
,请返回数组中第 k 个最大的元素。请注意,你需要找的是数组排序后的第
k
个最大的元素,而不是第k
个不同的元素。你必须设计并实现时间复杂度为
O(n)
的算法解决此问题。示例 1:
输入: [3,2,1,5,6,4], k = 2 输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6], k = 4 输出: 4
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
srand(time(NULL));
return qsort(nums,0,nums.size()-1,k);
}
int qsort(vector<int>& nums,int l,int r,int k)
{
if(l==r) return nums[l];
//随机选key
int key=getKey(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]);
}
//在三个区间内找第k大 [l,left] [left+1,right-1] [right,r]
int a=r-right+1,b=right-left-1;
if(a>=k) return qsort(nums,right,r,k);
else if(a+b>=k) return key;
else return qsort(nums,l,left,k-a-b);
}
int getKey(vector<int>& nums,int l,int r)
{
return nums[rand()%(r-l+1)+l];
}
};
4、库存管理III
仓库管理员以数组
stock
形式记录商品库存表,其中stock[i]
表示对应商品库存余量。请返回库存余量最少的cnt
个商品余量,返回 顺序不限。示例 1:
输入:stock = [2,5,7,4], cnt = 1 输出:[2]
示例 2:
输入:stock = [0,2,3,6], cnt = 2 输出:[0,2] 或 [2,0]
class Solution {
public:
vector<int> inventoryManagement(vector<int>& nums, int k) {
srand(time(NULL));
qsort(nums,0,nums.size()-1,k);
return {nums.begin(),nums.begin()+k};
}
void qsort(vector<int>& nums,int l,int r,int k)
{
if(l>=r) return;
//随机选key
int key=GetKey(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,l]
int a=left-l+1,b=right-left-1;
if(a>k) qsort(nums,l,left,k);
else if(a+b>=k) return;
else qsort(nums,right,r,k-a-b);
}
int GetKey(vector<int>& nums,int l,int r)
{
return nums[l+(rand()%(r-l+1))];
}
};
5、排序数组
给你一个整数数组
nums
,请你将该数组升序排列。你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为
O(nlog(n))
,并且空间复杂度尽可能小。示例 1:
输入:nums = [5,2,3,1] 输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0] 输出:[0,0,1,1,2,5]
class Solution {
public:
vector<int> tmp;//定义全局的辅助数组帮组归并排序
vector<int> sortArray(vector<int>& nums) {
tmp.resize(nums.size());
mergesort(nums,0,nums.size()-1);
return nums;
}
void mergesort(vector<int>& nums,int left,int right)
{
//递归结束条件
if(left>=right) return;
//选择中间开始递归 [left,mid] [mid+1,right]
int mid=left+(right-left)/2;
mergesort(nums,left,mid);
mergesort(nums,mid+1,right);
//归并排序主逻辑
int cur1=left,cur2=mid+1,i=0;
while(cur1<=mid&&cur2<=right)
{
if(nums[cur1]<nums[cur2]) tmp[i++]=nums[cur1++];
else tmp[i++]=nums[cur2++];
}
//解决没有排序的数据
while(cur1<=mid) tmp[i++]=nums[cur1++];
while(cur2<=right) tmp[i++]=nums[cur2++];
//将辅助数组的数据拷贝到原数组
for(int i=left;i<=right;i++)
nums[i]=tmp[i-left];
}
};
6、交易逆序对的总数
在股票交易中,如果前一天的股价高于后一天的股价,则可以认为存在一个「交易逆序对」。请设计一个程序,输入一段时间内的股票交易记录
record
,返回其中存在的「交易逆序对」总数。示例 1:
输入:record = [9, 7, 5, 4, 6] 输出:8 解释:交易中的逆序对为 (9, 7), (9, 5), (9, 4), (9, 6), (7, 5), (7, 4), (7, 6), (5, 4)。
class Solution {
public:
vector<int> tmp;
int reversePairs(vector<int>& nums) {
tmp.resize(nums.size());
return mergesort(nums,0,nums.size()-1);
}
int mergesort(vector<int>& nums,int left,int right)
{
if(left>=right) return 0;
int ret=0;
int mid=left+(right-left)/2;
//左右俩边各找一下
ret+=mergesort(nums,left,mid);
ret+=mergesort(nums,mid+1,right);
//归并排序(此时左右两边都是升序),顺便左右两边找一下逆序对
int i=0,cur1=left,cur2=mid+1;
while(cur1<=mid&&cur2<=right)
{
if(nums[cur1]>nums[cur2])
{
tmp[i++]=nums[cur1++];
ret+=right-cur2+1;
}
else
{
tmp[i++]=nums[cur2++];
}
}
while(cur1<=mid) tmp[i++]=nums[cur1++];
while(cur2<=right) tmp[i++]=nums[cur2++];
for(int i=left;i<=right;i++)
{
nums[i]=tmp[i-left];
}
return ret;
}
};
7、计算右侧小于当前元素的个数
给你一个整数数组
nums
,按要求返回一个新数组counts
。数组counts
有该性质:counts[i]
的值是nums[i]
右侧小于nums[i]
的元素的数量。示例 1:
输入:nums = [5,2,6,1] 输出:[2,1,1,0] 解释: 5 的右侧有 2 个更小的元素 (2 和 1) 2 的右侧仅有 1 个更小的元素 (1) 6 的右侧有 1 个更小的元素 (1) 1 的右侧有 0 个更小的元素
示例 2:
输入:nums = [-1] 输出:[0]
示例 3:
输入:nums = [-1,-1] 输出:[0,0]
class Solution {
public:
//ret记录结果,index记录下标,tmp1辅助排序,tmp2辅助index跟随排序
vector<int> ret,tmp1,tmp2,index;
vector<int> countSmaller(vector<int>& nums) {
int n=nums.size();
ret.resize(n);
tmp1.resize(n);
tmp2.resize(n);
//index初始化原数组下标
index.resize(n);
for(int i=0;i<n;i++) index[i]=i;
mergesort(nums,0,n-1);
return ret;
}
void mergesort(vector<int>& nums,int left,int right)
{
if(left>=right) return;
int mid=left+(right-left)/2;
mergesort(nums,left,mid);
mergesort(nums,mid+1,right);
int i=0,cur1=left,cur2=mid+1;
while(cur1<=mid&&cur2<=right)
{
if(nums[cur1]>nums[cur2])
{
ret[index[cur1]]+=right-cur2+1;//更新结果(当前值的结果要放到其原始下标的位置)
tmp1[i]=nums[cur1];//值放入辅助数组
tmp2[i++]=index[cur1++];//当前值的下标放入辅助数组
}
else
{
tmp1[i]=nums[cur2];
tmp2[i++]=index[cur2++];
}
}
//解决剩余排序问题
while(cur1<=mid)
{
tmp2[i]=index[cur1];
tmp1[i++]=nums[cur1++];
}
while(cur2<=right)
{
tmp2[i]=index[cur2];
tmp1[i++]=nums[cur2++];
}
for(int i=left;i<=right;i++)
{
nums[i]=tmp1[i-left];
index[i]=tmp2[i-left];
}
}
};
8、翻转对
给定一个数组
nums
,如果i < j
且nums[i] > 2*nums[j]
我们就将(i, j)
称作一个重要翻转对。你需要返回给定数组中的重要翻转对的数量。
示例 1:
输入: [1,3,2,3,1] 输出: 2
示例 2:
输入: [2,4,3,5,1] 输出: 3
class Solution {
public:
vector<int> tmp;
int reversePairs(vector<int>& nums) {
tmp.resize(nums.size());
return mergesort(nums,0,nums.size()-1);
}
int mergesort(vector<int>& nums,int left,int right)
{
if(left>=right) return 0;
int ret=0;
int mid=left+(right-left)/2;
//左右俩边各找一下
ret+=mergesort(nums,left,mid);
ret+=mergesort(nums,mid+1,right);
//在归并前找翻转对(数组有序,同向双指针)
int i=0,cur1=left,cur2=mid+1;
while(cur1<=mid&&cur2<=right)
{
if(nums[cur1]>2*(long long)nums[cur2])
{
ret+=right-cur2+1;
cur1++;
}
else cur2++;
}
//归并排序
i=0,cur1=left,cur2=mid+1;
while(cur1<=mid&&cur2<=right)
{
tmp[i++]=nums[cur1]>nums[cur2]?nums[cur1++]:nums[cur2++];
}
while(cur1<=mid) tmp[i++]=nums[cur1++];
while(cur2<=right) tmp[i++]=nums[cur2++];
for(int i=left;i<=right;i++)
{
nums[i]=tmp[i-left];
}
return ret;
}
};