当前位置: 首页 > news >正文

每日算法刷题Day44 7.8:leetcode前缀和4道题,用时1h40min

距离和

1.套路

图解
![[距离和.png]]

class Solution {
public:vector<long long> minOperations(vector<int>& nums, vector<int>& queries) {sort(nums.begin(), nums.end()); // 排序int n = nums.size(), m = queries.size();vector<long long> res(m);vector<long long> s(n + 1);s[0] = 0;for (int i = 0; i < n; ++i)s[i + 1] = s[i] + nums[i];for (int i = 0; i < m; ++i) {int q = queries[i];long long j = lower_bound(nums.begin(), nums.end(), q) -nums.begin();    // 找到第一个大于等于q的索引jlong long left = q * j - s[j]; // [0,j),绿色面积long long right = s[n] - s[j] - q * (n - j); // [j,n),蓝色面积res[i] = left + right;}return res;}
};
2.题目描述

1.给你一个 非递减 有序整数数组 nums
请你建立并返回一个整数数组 result,它跟 nums 长度相同,result[i] 等于 nums[i] 与数组中所有其他元素差的绝对值之和(条件)
换句话说, result[i] 等于 sum(|nums[i]-nums[j]|) ,其中 0 <= j < nums.lengthj != i (下标从 0 开始)。
2.给你一个下标从 0 开始的整数数组 nums 。现有一个长度等于 nums.length 的数组 arr 。对于满足 nums[j] == nums[i]j != i 的所有 jarr[i] 等于所有 |i - j| 之和(条件)。如果不存在这样的 j ,则令 arr[i] 等于 0
返回数组 arr(答案)
3.给你一个正整数数组 nums
同时给你一个长度为 m 的整数数组 queries 。第 i 个查询中,你需要将 nums 中所有元素变成 queries[i] 。你可以执行以下操作 任意 次:

  • 将数组里一个元素 增大 或者 减小 1
    请你返回一个长度为 m 的数组 answer(答案) ,其中 answer[i]是将 nums 中所有元素变成 queries[i] 的 最少 操作次数
    注意,每次查询后,数组变回最开始的值。
3.学习经验

1.首先是一个排序的数组,为了计算所有值到某一个定值q的距离和,可以二分lower_bound找到第一个大于等于q的值的索引j,从而划分成蓝色部分和绿色部分,再利用前缀和整个部分求和

1. 1685.有序数组中差绝对值之和(中等)

1685. 有序数组中差绝对值之和 - 力扣(LeetCode)

思想

1.给你一个 非递减 有序整数数组 nums
请你建立并返回一个整数数组 result,它跟 nums 长度相同,且result[i] 等于 nums[i] 与数组中所有其他元素差的绝对值之和。
换句话说, result[i] 等于 sum(|nums[i]-nums[j]|) ,其中 0 <= j < nums.lengthj != i (下标从 0 开始)。
2.跟套路一样,只不过已经排好序了

代码
class Solution {
public:vector<int> getSumAbsoluteDifferences(vector<int>& nums) {int n = nums.size();vector<int> res(n);vector<long long> s(n + 1);s[0] = 0;for (int i = 0; i < n; ++i)s[i + 1] = s[i] + nums[i];for (int i = 0; i < n; ++i) {int j =lower_bound(nums.begin(), nums.end(), nums[i]) - nums.begin();// [0,j)long long left = nums[i] * j - s[j];// [j,n)long long right = s[n] - s[j] - (n - j) * nums[i];res[i] = left + right;}return res;}
};
2. 2615.等值距离和(中等,学习)

1685. 有序数组中差绝对值之和 - 力扣(LeetCode)

思想

1.给你一个下标从 0 开始的整数数组 nums 。现有一个长度等于 nums.length 的数组 arr 。对于满足 nums[j] == nums[i]j != i 的所有 jarr[i] 等于所有 |i - j| 之和。如果不存在这样的 j ,则令 arr[i] 等于 0
返回数组 arr
2.因为题目是求j != i 的所有 jarr[i] 等于所有 |i - j| 之和,所以可以联想到图示的nums数组的值应该是下标,基线q就是是i,因为这些下标共性是nums[下标]相同,所以得先按nums[下标]分组,得到下标数组,这个用map来实现
3.还可以考虑去用增量的形式实现,如下图所示:
![[等值距离和.jpg]]

代码

相同元素分组+前缀和

class Solution {
public:vector<long long> distance(vector<int>& nums) {int n = nums.size();vector<long long> res(n);map<int, vector<long long>> mp; // 分组,相同的nums[i]的下标for (int i = 0; i < n; ++i) {mp[nums[i]].emplace_back(i);}for (auto& t : mp) {auto idxs = t.second;int m = idxs.size();vector<long long> s(m + 1);for (int i = 0; i < m; ++i)s[i + 1] = s[i] + idxs[i];for (int i = 0; i < m; ++i) {// q为idxs[i]int j = lower_bound(idxs.begin(), idxs.end(), idxs[i]) -idxs.begin();long long left = idxs[i] * j - s[j];long long right = s[m] - s[j] - idxs[i] * (m - j);res[idxs[i]] = left + right;}}return res;}
};

相同元素分组+考虑增量

class Solution {
public:vector<long long> distance(vector<int>& nums) {int n = nums.size();vector<long long> res(n);map<int, vector<long long>> mp; // 分组,相同的nums[i]的下标for (int i = 0; i < n; ++i) {mp[nums[i]].emplace_back(i);}for (auto& t : mp) {auto idxs = t.second; // idxs值为原先下标int m = idxs.size();long long s = 0; // 先算idxs[0]到其他位置的距离for (int i = 1; i < m; ++i)s += idxs[i] - idxs[0];res[idxs[0]] = s;for (int i = 1; i < m; ++i) {long long t =s + (2 * i - m) *(idxs[i] - idxs[i - 1]); // 考虑增量后idxs[i]位置的sres[idxs[i]] = t;s = t;}}return res;}
};
3.2602.使数组元素全部相等的最少操作次数(中等,学习)

2602. 使数组元素全部相等的最少操作次数 - 力扣(LeetCode)

思想

1.给你一个正整数数组 nums
同时给你一个长度为 m 的整数数组 queries 。第 i 个查询中,你需要将 nums 中所有元素变成 queries[i] 。你可以执行以下操作 任意 次:

  • 将数组里一个元素 增大 或者 减小 1
    请你返回一个长度为 m 的数组 answer ,其中 answer[i]是将 nums 中所有元素变成 queries[i]最少 操作次数。
    注意,每次查询后,数组变回最开始的值。
    2.如套路所示
代码

排序+二分+前缀和:

class Solution {
public:vector<long long> minOperations(vector<int>& nums, vector<int>& queries) {sort(nums.begin(), nums.end()); // 排序int n = nums.size(), m = queries.size();vector<long long> res(m);vector<long long> s(n + 1);s[0] = 0;for (int i = 0; i < n; ++i)s[i + 1] = s[i] + nums[i];for (int i = 0; i < m; ++i) {int q = queries[i];long long j = lower_bound(nums.begin(), nums.end(), q) -nums.begin();    // 找到第一个大于等于q的索引jlong long left = q * j - s[j]; // [0,j),绿色面积long long right = s[n] - s[j] - q * (n - j); // [j,n),蓝色面积res[i] = left + right;}return res;}
};

暴力方法:

class Solution {
public:vector<long long> minOperations(vector<int>& nums, vector<int>& queries) {int n=nums.size(),m=queries.size();vector<long long> res;for(int i=0;i<m;++i){long long cnt=0;for(int j=0;j<n;++j)    cnt+=abs(nums[j]-queries[i]);res.emplace_back(cnt);}return res;}
};

前缀异或和(异或先不考虑)

1.套路

从集合论到位运算,常见位运算技巧分类总结!
还是前缀和优化,只不过前缀和生成和计算的时候可以用异或优化,但是目前先不考虑这层优化,先写出来

2.题目描述

1.给你一个字符串 s,请你对 s 的子串进行检测。
每次检测,待检子串都可以表示为 queries[i] = [left, right, k]。我们可以 重新排列 子串 s[left], ..., s[right],并从中选择 最多 k 项替换成任何小写英文字母。
如果在上述检测过程中,子串可以变成回文形式的字符串,那么检测结果为 true,否则结果为 false(条件)
返回答案数组 answer[],其中 answer[i] 是第 i 个待检子串 queries[i] 的检测结果(答案)
注意:在替换时,子串中的每个字母都必须作为 独立的 项进行计数,也就是说,如果 s[left..right] = "aaa"k = 2,我们只能替换其中的两个字母。(另外,任何检测都不会修改原始字符串 s,可以认为每次检测都是独立的)

3.学习经验
1. 1177.构建回文串检测(中等,学习)
思想

1.给你一个字符串 s,请你对 s 的子串进行检测。
每次检测,待检子串都可以表示为 queries[i] = [left, right, k]。我们可以 重新排列 子串 s[left], ..., s[right],并从中选择 最多 k 项替换成任何小写英文字母。
如果在上述检测过程中,子串可以变成回文形式的字符串,那么检测结果为 true,否则结果为 false
返回答案数组 answer[],其中 answer[i] 是第 i 个待检子串 queries[i] 的检测结果。
注意:在替换时,子串中的每个字母都必须作为 独立的 项进行计数,也就是说,如果 s[left..right] = "aaa"k = 2,我们只能替换其中的两个字母。(另外,任何检测都不会修改原始字符串 s,可以认为每次检测都是独立的)
2.已经分析出对于每个查询,要计算出[left,right]出现次数为奇数次的字母的种类个数m,且m/2<=k返回True(重要分析)
3.现在考虑如何分析出优化,上面要得到[left,right]出现次数为奇数次的字母的种类个数m,可以用前缀和计算每种字母出现的次数,相比之前的前缀和数组,多了一个长度为26的第二维度,表示不同的字母,可以用固定大小的数组容器array<int,26>表示
4.异或的优化先暂时不考虑

代码

暴力超时:

class Solution {
public:vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {int n = queries.size();vector<bool> res(n);for (int i = 0; i < n; ++i) {int left = queries[i][0], right = queries[i][1], k = queries[i][2];map<char, long long> mps; // 字符-次数for (int j = left; j <= right; ++j)++mps[s[j]];long long cnt = 0;for (auto& mp : mps) {if (mp.second % 2)++cnt;}if (cnt / 2 <= k)res[i] = true;elseres[i] = false;}return res;}
};

前缀和优化:

class Solution {
public:vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {int n = s.size(), m = queries.size();vector<bool> res(m);vector<array<int, 26>> sum(n + 1);for (int i = 0; i < n; ++i) {sum[i + 1] = sum[i];++sum[i + 1][s[i] - 'a'];}for (int i = 0; i < m; ++i) {int left = queries[i][0], right = queries[i][1], k = queries[i][2];long long cnt = 0;for (int j = 0; j < 26; ++j) {cnt += (sum[right + 1][j] - sum[left][j]) % 2; // 奇数+1,偶数+0}if (cnt / 2 <= k)res[i] = true;elseres[i] = false;}return res;}
};
http://www.dtcms.com/a/270267.html

相关文章:

  • JVM 为什么使用元空间(Metaspace)替换了永久代(PermGen)?——深入理解 Java 方法区与类元数据存储的演进
  • 视频能转成gif动图吗?怎么弄?
  • [NOIP][C++]洛谷P1376 [USACO05MAR] Yogurt factory 机器工厂
  • 没合适的组合wheel包,就自行编译flash_attn吧
  • 行业实践案例:金融行业数据治理体系全景解析
  • Java 关键字详解:掌握所有保留关键字的用途与最佳实践
  • Apache Atlas编译打包,可运行包下载地址
  • DMA技术与音频数据的存储和播放
  • C++STL-vector
  • 【c++学习记录】状态模式,实现一个登陆功能
  • 笔试——Day1
  • numpy数据分析知识总结
  • VMware Workstation不可恢复错误:(vmx)点击设置闪退解决
  • [2-02-02].第03节:环境搭建 - Win10搭建ES集群环境
  • 一天一道Sql题(day03)
  • Choreographer
  • 基于大模型的心肌炎全病程风险预测与诊疗方案研究
  • 使用git生成ssh的ed25519密钥
  • 鲁成伟业精彩亮相第六届中国国际无人机及无人系统博览会
  • 一个vue项目的基本构成
  • DCL学习
  • 操作系统:基本概念
  • Java结构型模式---适配器模式
  • 蓝桥杯 第十六届(2025)真题思路复盘解析
  • 【Bluedroid】BLE 地址解析列表的初始化与清除机制(btm_ble_resolving_list_init)
  • 分布式接口幂等性的演进和最佳实践,含springBoot 实现(Java版本)
  • uniapp支持单选和多选的 Vue2 版本组件
  • 从UI设计到数字孪生实战演练:构建智慧金融的智能投顾平台
  • 第十四节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - Flask 后端 生产部署讲解
  • Python之面向对象和类