《六月集训》第八天——前缀和


前言

        
刷题坚持每一天,以下题目引用自:力扣(LeetCode)

💎一、题目一

🏆1.题目描述

原题链接:1838. 最高频元素的频数

        元素的 频数 是该元素在一个数组中出现的次数。
        给你一个整数数组 nums 和一个整数 k 。在一步操作中,你可以选择 nums 的一个下标,并将该下标对应元素的值增加 1 。
        执行最多 k 次操作后,返回数组中最高频元素的 最大可能频数 。

示例 1:
输入:nums = [1,2,4], k = 5
输出:3
解释:对第一个元素执行 3 次递增操作,对第二个元素执 2 次递增操作,此时 nums = [4,4,4] 。
4 是数组中最高频元素,频数是 3 。

🏆2.解题思路

🔑思路:

​         先排序,对于第一个值大于或等于后面的值(值加k)进行计数,不满足条件退出当前循环。比较是否比前一次频率大,保存大值。

🏆3.代码详解

int cmp(const void* q1, const void* q2){
    return *(int*)q2 - *(int*)q1;
}

int maxFrequency(int* nums, int numsSize, int k){
    qsort(nums, numsSize, sizeof(int), cmp);
    int i, j;
    int count = 1;
    int ans = 0;
    for(i = 0; i < numsSize; ++i){
        if(i > 0 && nums[i] == nums[i-1]) continue;
        int ret = k;
        for(j = i+1; j < numsSize; ++j){
            if(ret >= nums[i]-nums[j]){
                ret -= nums[i]-nums[j];
                ++count;
            }
            else  break;
        }
        ans = ans > count ? ans : count;
        count = 1;
    }
    return ans;
}

💎二、题目二

🏆1.题目描述

原题链接:1590. 使数组和能被 P 整除

        给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空),使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。
        请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回 -1 。
        子数组 定义为原数组中连续的一组元素。

示例 1:
输入:nums = [3,1,4,2], p = 6
输出:1
解释:nums 中元素和为 10,不能被 p 整除。我们可以移除子数组 [4] ,剩余元素的和为 6 。

🏆2.解题思路

🔑思路:

​         第一版本暴力求解超时。第二版本C++,哈希+前缀 ,用哈希建做索引存储余数,值存数组索引。当一个连续子数组的余数在hash里出现过时,就用当前索引值减hash里的值,就是去除连续子数组的长度。接着判断取最小的就可以。

🏆3.代码详解

/*超时版本,
  超时版本,
  超时版本*/
int minSubarray(int* nums, int numsSize, int p){
    long long ret = 0;
    for(int i = 0; i < numsSize; ++i){
        ret += nums[i]; 
    }
    if(ret % p == 0) return 0;
    long long sum = 0;
    int min = 1000000001;
    int count = 0;
    for(int i = 0; i < numsSize; ++i){
        count = 0;
        sum = 0;
        for(int j = i; j < numsSize; ++j){
            sum += nums[j];
            ++count;
            if((ret - sum) != 0 && (ret - sum) % p == 0)
                min = min > count ? count : min;   
        }
    } 
    return min == 1000000001 ? -1 : min;
}
class Solution {
public:
    int minSubarray(vector<int>& nums, int p) {
        int len = nums.size();
        long long ret = 0;
        long long sum = 0;
        int ans = 1000000001;
        unordered_map<int, int> hash;
        hash[0] = 0;

        for(int i = 0; i < len; ++i) ret += nums[i]%p;
        ret %= p;
        if(ret % p == 0) return 0;
        printf("%d\n", ret);
        for (int i = 1; i <= len; ++i) {
            sum += nums[i-1]%p; 
            int x = (sum - ret + p) % p; 
            if (hash.count(x)){
                ans = min(ans, i-hash[x]);
                printf("%d,%d\n",i,ans);
            }
            hash[sum%p] = i; 
        }
        if (ans == len) return -1; 
        return ans;
    }
};

💎三、题目三

🏆1.题目描述

原题链接:1589. 所有排列中的最大和

        有一个整数数组 nums ,和一个查询数组 requests ,其中 requests[i] = [starti, endi] 。第 i 个查询求 nums[starti] + nums[starti + 1] + … + nums[endi - 1] + nums[endi] 的结果 ,starti 和 endi 数组索引都是 从 0 开始 的。
        你可以任意排列 nums 中的数字,请你返回所有查询结果之和的最大值。
        由于答案可能会很大,请你将它对 109 + 7 取余 后返回。

示例 1:
输入:nums = [1,2,3,4,5], requests = [[1,3],[0,1]]
输出:19
解释:一个可行的 nums 排列为 [2,1,3,4,5],并有如下结果:
requests[0] -> nums[1] + nums[2] + nums[3] = 1 + 3 + 4 = 8
requests[1] -> nums[0] + nums[1] = 2 + 1 = 3
总和为:8 + 3 = 11。
一个总和更大的排列为 [3,5,4,2,1],并有如下结果:
requests[0] -> nums[1] + nums[2] + nums[3] = 5 + 4 + 2 = 11
requests[1] -> nums[0] + nums[1] = 3 + 5 = 8
总和为: 11 + 8 = 19,这个方案是所有排列中查询之和最大的结果。

🏆2.解题思路

🔑思路:
        链接:什么是差分数组
​        用差分数组记录区间里值出现的次数,前缀和还原。利用排序把最大的值与出现次数最多的相乘依次循环。求出最大值。

🏆3.代码详解

#define mod 1000000007
int cmp(const void*q1, const void*q2){
    return *(int*)q1 - *(int*)q2;
}
int maxSumRangeQuery(int* nums, int numsSize, int** requests, int requestsSize, int* requestsColSize){
    int* diff = (int*)malloc(sizeof(int)*numsSize);
    long long ans = 0;
    memset(diff, 0, sizeof(int)*numsSize);
    for(int i = 0; i < requestsSize; ++i){
        diff[requests[i][0]]++;
        if(requests[i][1]+1 < numsSize){
            diff[requests[i][1]+1]--;
        }
    }
    for(int i = 1; i < numsSize; ++i){
        diff[i] += diff[i-1];
    }
    qsort(diff, numsSize, sizeof(int), cmp);
    qsort(nums, numsSize, sizeof(int), cmp);
     for(int i = 0; i < numsSize; ++i){
       ans += ((long long)nums[i] * diff[i]) % mod;
    }
    return ans%mod;
}

💎四、星球推荐

        星球链接:英雄算法联盟

星球里有什么?
        【朋友圈】一个极致精准的自律、编程、算法的小圈子。
        【算法集训】以月为单位组织算法集训,每天四题,风雨无阻。
        【排行榜】每天、每周都会有榜单,激励大家不断进步,不断成长。
        【个人规划】每个人都写好自己的规划,也可以查看他人的规划,时刻警醒自己不掉队。
        【打卡挑战】每日一题打卡、每日早起打卡、算法集训打卡、规划完成情况打卡。
在星球里做什么?
        目前星球人数达到360+,在星球里你能够遇到一群志同道合之人,因为都是花钱进来的,你不会看到任何浑水摸鱼的人,每个人都有自己的每月规划,星主每月都会组织算法集训,每天一起刷题,你可以看到别人的解题报告,取其之长,补己之短。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值