【每日刷题】Day42
🥕个人主页:开敲🍉
🔥所属专栏:每日刷题🍍
🌼文章目录🌼
1. 826. 安排工作以达到最大收益 - 力扣(LeetCode)
2. 2099. 找到和最大的长度为 K 的子序列 - 力扣(LeetCode)
3. 2335. 装满杯子需要的最短总时长 - 力扣(LeetCode)
1. 826. 安排工作以达到最大收益 - 力扣(LeetCode)
//思路:本题主体思路为排序,但是有个问题需要解决——排序后难度对应的利润会发生变化。我们可以将难度数组中的元素全部按照如下规则变化:×数组长度后+自身下标,当我们需要知道其对应的利润时可以直接 % 上数组长度,当我们需要求得其原本的长度时,可以直接 - 下标再 ÷ 数组长度即可。
int compare(const void* a,const void* b)
{
return (*(int*)a-*(int*)b);
}
int maxProfitAssignment(int* difficulty, int difficultySize, int* profit, int profitSize, int* worker, int workerSize)
{
for(int i = 0;i<difficultySize;i++)
{
difficulty[i] = difficulty[i]*difficultySize+i;//将难度数组元素变化
}
qsort(difficulty,difficultySize,sizeof(int),compare);//对难度数组排序
qsort(worker,workerSize,sizeof(int),compare);//对工人数组排序
int w = 0;
int ans = 0;
int i = 0;
int flag = 0;
int max = 0;
while(w<workerSize)
{
if(flag==0&&((difficulty[i]-i)/difficultySize)>worker[w])//用于处理工人数组中所有工人都没有能力处理工作的情况
{
w++;
flag = 0;
}
else if(i<difficultySize&&((difficulty[i]-i)/difficultySize)<=worker[w])//找到当前工人所能处理的工作中的最大利润的工作,记录最大利润
{
max = max>profit[difficulty[i]%difficultySize]?max:profit[difficulty[i]%difficultySize];
i++;
flag = 1;
}
if(i==difficultySize||(flag==1&&((difficulty[i]-i)/difficultySize)>worker[w]))//到遍历到当前工人的能力范围之外的工作时,将结果+上所记录的最大利润,向后继续遍历工人数组
{
ans+=max;
w++;
}
}
return ans;
}
2. 2099. 找到和最大的长度为 K 的子序列 - 力扣(LeetCode)
//思路:本题思路还是排序,难点还是在于题目要求最后返回的元素顺序不能改变,也就是下标顺序不能改变,因此我们如法炮制通过元素的变换使得后面还能够找到下标。这里我们将题目原数组中的元素进行变换,随后对其进行降序排序(元素大小由高到低)。再使用一个数组记录排序后的原数组的前k个元素原来的下标,随后再对这个数组进行升序排序(使得下标由低到高),这样就既能够找到原数组最大的k个元素,又能够保证下标顺序不会改变。然后我们需要使用一个数组存储最初的没有做任何操作的原数组,通过前面存储的排好序的下标数组,找到原数组中满足题目要求的子序列。
int compare1(const void* a,const void* b)
{
return (*(int*)b-*(int*)a);
}
int compare2(const void* a,const void* b)
{
return (*(int*)a-*(int*)b);
}
int* maxSubsequence(int* nums, int numsSize, int k, int* returnSize)
{
int tmp[1000] = {0};
memcpy(tmp,nums,sizeof(int)*numsSize);
int flag[numsSize];
int* ans = (int*)malloc(sizeof(int)*numsSize);
for(int i = 0;i<numsSize;i++)//对题目所给数组中的元素进行变换
{
if(nums[i]<0)
{
nums[i] = nums[i]*numsSize-i;
}
else
{
nums[i] = nums[i]*numsSize+i;
}
}
qsort(nums,numsSize,sizeof(int),compare1);//进行降序排序(为了找到最大的k个元素)
for(int i = 0;i<k;i++)
{
int tmp = 0;
if(nums[i]<0)//获取最大的k个元素原本的下标
{
tmp = (nums[i]*-1)%numsSize;
}
else
{
tmp = nums[i]%numsSize;
}
flag[i] = tmp;
}
qsort(flag,k,sizeof(int),compare2);//对最大的k个元素原本的下标进行升序排序
for(int i = 0;i<k;i++)
{
ans[i] = tmp[flag[i]];//通过下标找到元素,构成满足题目要求的子序列
}
*returnSize = k;
return ans;
}
3. 2335. 装满杯子需要的最短总时长 - 力扣(LeetCode)
//思路:堆。将数组用大堆存储。每次将堆中最大的两个元素-1,直到堆顶的元素为0。
typedef int HPDataType;
//交换
void Swap(HPDataType* child, HPDataType* parents)
{
HPDataType tmp = *child;
*child = *parents;
*parents = tmp;
}
//向上调整
void HPAdjustUp(HPDataType* arr,int child)
{
int parents = (child - 1) / 2;
while (child > 0&&arr[child]>arr[parents])
{
Swap(&arr[child], &arr[parents]);
child = parents;
parents = (child - 1) / 2;
}
}
//向下调整
void HPAdjustDown(HPDataType* arr, int parents,int size)
{
int child = parents * 2 + 1;
while (child < size)
{
if (child+1<size&&arr[child + 1] > arr[child])
{
child++;
}
if (arr[child] > arr[parents])
{
Swap(&arr[child], &arr[parents]);
parents = child;
child = parents * 2 + 1;
}
else
{
break;
}
}
}
int fillCups(int* amount, int amountSize)
{
int count = 0;
for(int i = 0;i<amountSize;i++)
{
HPAdjustUp(amount,i);//将数据用大堆的形式存储
}
while(amount[0]>0)
{
amount[0]--;//由于是大堆存储,因此堆顶数据一定是最大的
if(amount[1]>amount[2])//找到堆中第二大的元素
{
amount[1]--;
}
else
{
amount[2]--;
}
HPAdjustDown(amount,0,amountSize);//将堆中最大的元素-1后需要更新堆,确保堆依然是大堆
count++;//计算总时长
}
return count;
}