题目
给你两个长度相等下标从 0 开始的整数数组 nums1
和 nums2
。每一秒,对于所有下标 0 <= i < nums1.length
,nums1[i]
的值都增加 nums2[i]
。操作 完成后 ,你可以进行如下操作:
- 选择任一满足
0 <= i < nums1.length
的下标i
,并使nums1[i] = 0
。
同时给你一个整数 x
。
请你返回使 nums1
中所有元素之和 小于等于 x
所需要的 最少 时间,如果无法实现,那么返回 -1
。
示例 1:
输入:nums1 = [1,2,3], nums2 = [1,2,3], x = 4 输出:3 解释: 第 1 秒,我们对 i = 0 进行操作,得到 nums1 = [0,2+2,3+3] = [0,4,6] 。 第 2 秒,我们对 i = 1 进行操作,得到 nums1 = [0+1,0,6+3] = [1,0,9] 。 第 3 秒,我们对 i = 2 进行操作,得到 nums1 = [1+1,0+2,0] = [2,2,0] 。 现在 nums1 的和为 4 。不存在更少次数的操作,所以我们返回 3 。
示例 2:
输入:nums1 = [1,2,3], nums2 = [3,3,3], x = 4 输出:-1 解释:不管如何操作,nums1 的和总是会超过 x 。
提示:
1 <= nums1.length <= 103
1 <= nums1[i] <= 103
0 <= nums2[i] <= 103
nums1.length == nums2.length
0 <= x <= 106
思路
这每日一题有点难啊,不愧是困难难度,优化了好久也才959/1272,求大佬教教为啥
AA宏注释掉就是提交到leetcode的,AA不注释就是本地调试的,有兴趣的可以自己调试下。
首先明确一点,虽然题目说是可以清零,但是这个题目是小于等于而不是等于x,所以不会出现不清零的情况,所以直接清零就好了。
先写个结构体存n1/n2,这个比率我愿称之为n1的阳寿比,这个比率越大,在某些情况下,说明这个n1的阳寿太长了,得赶紧砍掉,这样就可以保证整个数组成长曲线是最低的,在数字特别大的情况下,这个比率可以优先删除大的数字。
之所以写了两个while,是因为在某些情况下,无脑删除整个数组最大的数有可能会比砍阳寿更快,因为有些初始值大且增长值也较大的,在增长起来之前,初始值清楚就可以达到sum<x的目的,因此得做一遍检查。
代码
#include <stdio.h>
#include <limits.h>
#define AA
#ifdef AA
#define print printf
#else
#define print
#endif
typedef struct Node {
int n1;
int n2;
double n1Divn2; // 用于存储 n1 与 n2 的除法结果
}Node_t;
int cntSum(Node_t* num, int size){
int sum = 0;
for (int i = 0; i < size; i++){
sum += num[i].n1;
}
return sum;
}
void frashRatio(Node_t* nums, int size)
{
for (int i = 0; i < size; i++){
nums[i].n1Divn2 = nums[i].n2 != 0 ? (double)(nums[i].n1) / nums[i].n2 : 0;
}
}
Node_t* searchMaxRatioNode(Node_t* nums, int size)
{
Node_t* maxRatioNode = &nums[0];
for (int i = 1; i < size; i++){
if (nums[i].n1Divn2 > maxRatioNode->n1Divn2)
{
maxRatioNode = &nums[i];
}
else if((nums[i].n1Divn2 == maxRatioNode->n1Divn2) && (nums[i].n1 <= maxRatioNode->n1))
{
maxRatioNode = &nums[i];
}
}
return maxRatioNode;
}
int minimumTime(int* nums1, int nums1Size, int* nums2, int nums2Size, int x) {
int time = 0;
int totalNum = 0;
int size = nums1Size;
Node_t nums[size]; // 初始化节点数组
unsigned int tmp_time = 0;
// 初始化节点数组
for (int i = 0; i < size; i++)
{
nums[i].n1 = nums1[i];
nums[i].n2 = nums2[i];
nums[i].n1Divn2 = (nums2[i] != 0) ? ((double)nums1[i] / nums2[i]) : 0;
}
int sum = cntSum(nums, size);
print("sum = %d\n", sum);
if (sum <= x)
return 0; // 检查初始条件
while (sum > x) {
for (int i = 0; i < size; i++) {
nums[i].n1 += nums[i].n2; // 增加 n2 值
print("%d ", nums[i].n1);
}
frashRatio(nums,size);
Node_t* maxRatioNode = searchMaxRatioNode(nums, size);
time++; // 增加时间
sum = cntSum(nums, size); // 重新计算总和
print("sum = %d\n", sum);
for (int i = 0; i < size; i++)
{
if((sum - nums[i].n1) <= x)
{
goto tag;
}
}
print("clear num[%d].n val = %d\n\n",(maxRatioNode - nums), maxRatioNode->n1);
maxRatioNode->n1 = 0; // 将选中的节点的 n1 值归零
// sleep(1);
if(time > 1000)
{
time = -1;
break;
}
}
tag:
print("opt2\n");
for (int i = 0; i < size; i++)
{
nums[i].n1 = nums1[i];
nums[i].n2 = nums2[i];
nums[i].n1Divn2 = (nums2[i] != 0) ? ((double)nums1[i] / nums2[i]) : 0;
}
while (tmp_time < 100)
{
for (int i = 0; i < size; i++) {
nums[i].n1 += nums[i].n2; // 增加 n2 值
print("%d ", nums[i].n1);
}
tmp_time++; // 增加时间
sum = cntSum(nums, size); // 重新计算总和
print("sum = %d\n", sum);
Node_t *maxnode = &nums[0];
for (int i = 1; i < size; i++)
{
if(maxnode->n1 < nums[i].n1)
{
maxnode = &nums[i];
}
}
if((sum - maxnode->n1) <= x)
{
break;
}
print("clear num[%d].n val = %d\n\n",(maxnode - nums), maxnode->n1);
maxnode->n1 = 0;
}
print("time = %d, tmp_time = %d\n",time, tmp_time);
if(time == -1 && tmp_time < 999)
{
return tmp_time;
}
else if(time == -1)
return time;
return time < tmp_time ? time : tmp_time;
}
#ifdef AA
int main(void)
{
int a[] = {1,7,9,4,8,8,1};
int b[] = {2,2,3,2,0,1,0};
int size = sizeof(a)/ sizeof(int);
int ret = minimumTime(a,size,b,size,20);
printf("\nret = %d\n",ret);
}
#endif