您现在的位置是:首页 >技术杂谈 >【力扣周赛】第342场周赛网站首页技术杂谈
【力扣周赛】第342场周赛
【力扣周赛】第342场周赛
6387:计算列车到站时间
题目描述
描述:给你一个正整数 arrivalTime 表示列车正点到站的时间(单位:小时),另给你一个正整数 delayedTime 表示列车延误的小时数。
返回列车实际到站的时间。
注意,该问题中的时间采用 24 小时制。
输入: arrivalTime = 15, delayedTime = 5
输入: 20
解释:列车正确点到站时间是15:00,延错5小时,所以列车实际到站的时间是15 + 5 = 20(20:00)。
输入: arrivalTime = 13, delayedTime = 11
输入: 0
解释:列车正确点到站时间是 13:00 ,延错 11 点钟,所以列车实际到站的时间是 13 + 11 = 24(在中楶桶 24 00 :00 ,所以返回 0)。
1 <= arrivaltime < 24
1 <= delayedTime <= 24
解题思路
思路:使用列车正点到站时间arrivalTime与列车延误小时数delayedTime相加再模以24即可。
int findDelayedArrivalTime(int arrivalTime, int delayedTime) {
return (arrivalTime+delayedTime)%24;
}
6391:倍数求和
题目描述
描述:给你一个正确的整数n,请你计算在[1,n]范围内能被3、5、7整除的所有整数之和。
返回一个整数,用于表示给定范围内所有满足约条件的数字之和。
输入: n = 7
输入: 21
解释:在[1, 7]范围内能被 3、5、7 整除的所有整数分别是 3、5、6、7。数字之和为21。
输入: n = 10
输入: 40
解释:在[1, 10]范围内能被 3、5、7 整除的所有整数分别是 3、5、6、7、9、10。数字之和为40。
输入: n = 9
输入: 30
解释:在[1, 9]范围内能被 3、5、7 整除的所有整数分别是 3、5、6、7、9。数字之和为30。
1 <= n <= 103
解题思路
思路:使用res记录结果,初始化为0,从1遍历到n,判断i%3==0或者i%5==0或者i%7==0,如果是则将i加入res。
int sumOfMultiples(int n) {
int res=0;
for(int i=3;i<=n;i++)
if(i%3==0||i%5==0||i%7==0)
res+=i;
return res;
}
6390:滑动子数组的美丽值
题目描述
描述:给你一个长度为 n 的整数数组 nums ,请你求出每个长度为 k 的子数组的 美丽值 。
一个子数组的 美丽值 定义为:如果子数组中第 x 小整数 是 负数 ,那么美丽值为第 x 小的数,否则美丽值为 0 。
请你返回一个包含 n - k + 1 个整数的数组,依次 表示数组中从第一个下标开始,每个长度为 k 的子数组的 美丽值 。
子数组指的是数组中一段连续 非空 的元素序列。
输入:nums = [1,-1,-3,-2,3], k = 3, x = 2
输出:[-1,-2,-2]
解释:总共有 3 个 k = 3 的子数组。
第一个子数组是 [1, -1, -3] ,第二小的数是负数 -1 。
第二个子数组是 [-1, -3, -2] ,第二小的数是负数 -2 。
第三个子数组是 [-3, -2, 3] ,第二小的数是负数 -2 。
输入:nums = [-1,-2,-3,-4,-5], k = 2, x = 2
输出:[-1,-2,-3,-4]
解释:总共有 4 个 k = 2 的子数组。
[-1, -2] 中第二小的数是负数 -1 。
[-2, -3] 中第二小的数是负数 -2 。
[-3, -4] 中第二小的数是负数 -3 。
[-4, -5] 中第二小的数是负数 -4 。
输入:nums = [-3,1,2,-3,0,-3], k = 2, x = 1
输出:[-3,0,-3,-3,-3]
解释:总共有 5 个 k = 2 的子数组。
[-3, 1] 中最小的数是负数 -3 。
[1, 2] 中最小的数不是负数,所以美丽值为 0 。
[2, -3] 中最小的数是负数 -3 。
[-3, 0] 中最小的数是负数 -3 。
[0, -3] 中最小的数是负数 -3 。
n == nums.length
1 <= n <= 105
1 <= k <= n
1 <= x <= k
-50 <= nums[i] <= 50
解题思路
思路:遍历滑动窗口,使用i表示滑动窗口起始值,使用j表示滑动窗口元素下标,窗口大小为k,使用优先队列存储长度为x的大根堆,其中第x小的元素即长度为x的大根堆的堆顶元素。具体做法如下:当堆的大小小于x时将当前元素压入堆,反之当堆的大小等于x时,判断当前元素与堆顶元素的关系,如果当前元素小于堆顶元素,则弹出堆顶元素,再压入当前元素,遍历完一个窗口后,判断堆顶元素是否小于0,如果是则加入堆顶元素到结果数组res中,反之加入0。(超时)
vector<int> getSubarrayBeauty(vector<int>& nums, int k, int x) {
int n=nums.size();
vector<int> res;
for(int i=0;i<n&&i+k-1<n;i++)
{
priority_queue<int> pq; //长度为x的优先级队列 大根堆 第x小
for(int j=i;j<i+k&&j<n;j++)
{
if(pq.size()==x) //长度等于x判断当前元素和堆顶关系
{
if(nums[j]<pq.top()) //如果当前元素小于堆顶元素 弹出堆顶元素 压入当前元素
{
pq.pop();
pq.push(nums[j]);
}
}
else if(pq.size()<x) //长度小于x压入堆
pq.push(nums[j]);
}
if(pq.top()<0)
res.push_back(pq.top());
else
res.push_back(0);
}
return res;
}
int get_min(deque<int> dq,int x)
{
priority_queue<int> pq;
int temp;
while(dq.size()) //注意dq.size()在不断变化
{
temp=dq.front();
if(pq.size()==x)
{
if(temp<pq.top())
{
pq.pop();
pq.push(temp);
}
}
else if(pq.size()<x)
pq.push(temp);
dq.pop_front();
}
return pq.top();
}
vector<int> getSubarrayBeauty(vector<int>& nums, int k, int x) {
int n=nums.size();
vector<int> res;
deque<int> dq;
int minx;
for(int i=0;i<n;i++)
{
dq.push_back(nums[i]);
if(dq.size()==k)
{
minx=get_min(dq,x);
if(minx<0)
res.push_back(minx);
else
res.push_back(0);
dq.pop_front();
}
}
return res;
}
上述方法都超时啦!!要想办法优化哇!!
优化:由于元素值范围为-50到50,所以可以使用一维数组记录元素值与元素个数的映射关系,因为存在负数,所以可以将整体元素值加以50,这样-50~50就转化为0~100,即可以创建一个长度为100的hash数组。具体实现方法是:首先记录第一个窗口的第x小的数值,其是遍历下标为0~49的hash数组,统计负数-50~-1的个数,如果对应个数大于等于x,则表明对应元素即为第x小的元素,返回i-50,反之第x小的元素不为负数,即返回0;接着遍历剩余的剩余窗口,每次将窗口中进一个元素出一个元素再求窗口内的第x小的数值。
int getMin(int hash[],int x) //注意数组传参int hash[]
{
int count=0; //记录负数出现的次数
for(int i=0;i<=49;i++) //-50~-1对应0~49
{
count+=hash[i];
if(count>=x)
return i-50;
}
return 0; //没有则返回0
}
vector<int> getSubarrayBeauty(vector<int>& nums, int k, int x) {
int n=nums.size();
vector<int> res(n-k+1);
int hash[101]={0}; //元素-元素个数 -50~50 将其元素值加50对应
for(int i=0;i<k;i++) //统计第一个窗口元素个数
hash[nums[i]+50]++;
res[0]=getMin(hash,x); //计算第一个窗口第x小值
for(int i=k;i<n;i++)
{
hash[nums[i]+50]++; //进一个元素
hash[nums[i-k]+50]--; //出一个元素
res[i-k+1]=getMin(hash,x);
}
return res;
}
6392:使数组所有元素变成1的最少操作次数
题目描述
描述:给你一个下标从 0 开始的 正 整数数组 nums 。你可以对数组执行以下操作 任意 次:
选择一个满足 0 <= i < n - 1 的下标 i ,将 nums[i] 或者 nums[i+1] 两者之一替换成它们的最大公约数。
请你返回使数组 nums 中所有元素都等于 1 的 最少 操作次数。如果无法让数组全部变成 1 ,请你返回 -1 。
两个正整数的最大公约数指的是能整除这两个数的最大正整数。
输入:nums = [2,6,3,4]
输出:4
解释:我们可以执行以下操作:
- 选择下标 i = 2 ,将 nums[2] 替换为 gcd(3,4) = 1 ,得到 nums = [2,6,1,4] 。
- 选择下标 i = 1 ,将 nums[1] 替换为 gcd(6,1) = 1 ,得到 nums = [2,1,1,4] 。
- 选择下标 i = 0 ,将 nums[0] 替换为 gcd(2,1) = 1 ,得到 nums = [1,1,1,4] 。
- 选择下标 i = 2 ,将 nums[3] 替换为 gcd(1,4) = 1 ,得到 nums = [1,1,1,1] 。
输入:nums = [2,10,6,14]
输出:-1
解释:无法将所有元素都变成 1 。
2 <= nums.length <= 50
1 <= nums[i] <= 106
解题思路
使数组所有元素变成1的最少操作次数:最直观的想法是,分类讨论。如果数组元素中有1,则操作次数是n-cnt1次;如果所有元素的gcd大于1,那么无法将所有元素变成1,直接返回-1;如果元素中没有1,那么求长度最短的gcd为1的连续子数组的长度,首先将该子数组变出一个1,其需要min_size-1次,接着将其所有变成1,其需要n-1次,故一共min_size+n-2次。
int minOperations(vector<int>& nums)
{
int n=nums.size();
int gcd_all=0; //当前所有元素的gcd值 0和任何为任何
int cnt1=0; //1的个数
for(int num:nums)
{
gcd_all=gcd(gcd_all,num); //记录所有元素的gcd
cnt1+=num==1; //当当前元素为1记录
}
if(gcd_all>1) return -1; //所有gcd大于1不行
if(cnt1) return n-cnt1; //元素中有1
//元素中没1找gcd为1的连续子数组
int min_size=n; //gcd为1的最短连续子数组
for(int i=0;i<n;i++)
{
int g=0;
for(int j=i;j<n;j++)
{
g=gcd(g,nums[j]);
if(g==1)
{
min_size=min(min_size,j-i+1);
break;
}
}
}
return min_size+n-2; //(min_size-1)+(n-1)
}
总结:C++中有gcd()函数,其求解两个数的gcd,即最大公约数。