前缀和之距离和
参考资料来源灵神在力扣所发的题单,仅供分享学习笔记和记录,无商业用途。
核心思路:在给定的区间内根据当前数划分小于和大于部分分别求距离
应用场景:一维场景:数组中「区间距离和」
问题示例:
给定一个数组 nums
,求任意区间 [L, R]
内所有元素到某个点(如区间中点、特定索引)的距离和。
模板题 1685. 有序数组中差绝对值之和
class Solution {
public:vector<int> getSumAbsoluteDifferences(vector<int>& nums) {//核心思路:在区间内分别找到大于小于区间,分开计算再相加即可。//前缀和计算距离和公式:小于数据的数量*当前数-小于区间前缀和+大于区间前缀和-大于数据的数量*当前数int n=nums.size();vector<int> ret(n);vector<int> ans(n+1);for(int i=0;i<n;i++) ans[i+1]=ans[i]+nums[i];for(int i=0;i<n;i++){ret[i]=i*nums[i]-ans[i]+ans[n]-ans[i+1]-(n-i-1)*nums[i];}return ret;}
};
2615. 等值距离和
题意:
给定一个整数数组,要求获得一个数组,数组元素由给定数据的下标与相同元素的下标距离和生成
核心思路:
采用哈希表将相同元素的所有下标全部存储
计算下标前缀和,遍历当前元素下标数组,在根据距离和公式计算出结果存储在当前下表内
class Solution {
public:vector<long long> distance(vector<int>& nums) {//题意:给定一个整数数组,要求获得一个数组,数组元素由给定数据的下标与相同元素的下标距离和生成//核心思路:采用哈希表将相同元素的所有下标全部存储//计算下标前缀和,遍历当前元素下标数组,在根据距离和公式计算出结果存储在当前下表内int n=nums.size();unordered_map<int,vector<int>> group;vector<long long> ret(n);for(int i=0;i<n;i++) group[nums[i]].push_back(i);for(auto& [_,a]:group){int m=a.size();vector<long long> s(m+1);for(int i=0;i<m;i++) s[i+1]=s[i]+a[i];for(int i=0;i<m;i++){long long target=a[i];long long l=target*i-s[i];long long r=s[m]-s[i+1]-target*(m-i-1);ret[target]=l+r;}}return ret;}
};
2602. 使数组元素全部相等的最少操作次数
题意:根据操作数组,将原数组数据变成当前数据需要的最少操作次数存放到新数组中
核心思路:
先排序,后根据二分01模型划分小于当前元素区间和大于等于当前元素区间
根据前缀和与距离和公式:计算得出原数据变成当前元素需要的最少操作次数
class Solution {
public://二分01模型,找到大于等于k的第一位,如果不存在默认收敛到最后一位下标int search_01(vector<int>& nums, int k){int l=0,r=nums.size()-1,mid;while(l<r){mid=l+((r-l)>>1);if(nums[mid]>=k) r=mid;else l=mid+1;}return l;}vector<long long> minOperations(vector<int>& nums, vector<int>& queries) { //题意:根据操作数组,将原数组数据变成当前数据需要的最少操作次数存放到新数组中//核心思路:先排序,后根据二分01模型划分小于当前元素区间和大于等于当前元素区间//根据前缀和与距离和公式:计算得出原数据变成当前元素需要的最少操作次数sort(nums.begin(),nums.end());vector<long long> ret(queries.size());vector<long long> ans(nums.size()+1);for(int i=0;i<nums.size();i++) ans[i+1]=ans[i]+nums[i];for(int i=0;i<queries.size();i++){long long idx=search_01(nums,queries[i]);if(nums[idx]<queries[i]) ret[i]=nums.size()*queries[i]-ans[nums.size()];else ret[i]=idx*queries[i]-ans[idx]+ans[nums.size()]-ans[idx]-(nums.size()-idx)*queries[i];}return ret;}
};
2968. 执行操作使频率分数最大
题意:给定一个整数数组和操作次数,每次操作能对数据+1or-1。求在操作次数内改变数据使得让某个元素出现次数最多。
思路:
进行升序排序,进行二分答案10模型搜索。
检查函数:检查是否存在长度为ret的连续子数组,其调整为同一值的总操作数 ≤ k
对于一组有序数,使「所有元素与目标值的绝对值之和最小」的目标值,就是这组数的中位数。
根据给定的ret答案,又根据有序原则采用长度为ret长度的滑动窗口维护,以中位数作为变化数。枚举滑窗中的中位数进行计算窗口内距离和,满足<=k说明当前答案可以满足。
class Solution {
public://检查函数:检查是否存在长度为ret的连续子数组,其调整为同一值的总操作数 ≤ k//对于一组有序数,使「所有元素与目标值的绝对值之和最小」的目标值,就是这组数的中位数。//根据给定的ret答案,又根据有序原则采用长度为ret长度的滑动窗口维护,以中位数作为变化数。枚举滑窗中的中位数进行计算窗口内距离和,满足<=k说明当前答案可以满足bool check(vector<int>& nums, vector<long long>& ans, long long k, int ret) {int n=nums.size();for(int left=0;left<=n-ret;left++){int right=left+ret-1; //滑窗右边界int mid=(left+right)/2; //中位数long long target=nums[mid]; //变化数//左侧需要操作数 long long l=target*(mid-left)-(ans[mid]-ans[left]);//右侧需要操作数 long long r=ans[right+1]-ans[mid+1]-target*(right-mid);if(l+r<=k) return true;}return false;}int maxFrequencyScore(vector<int>& nums, long long k) {//题意:给定一个整数数组和操作次数,每次操作能对数据+1or-1。求在操作次数内改变数据使得让某个元素出现次数最多//核心思路:进行升序排序,进行二分答案10模型搜索。if(k==0){int buff=0;unordered_map<int,int> map;for(auto x:nums){map[x]++;buff=max(buff,map[x]);}return buff;}sort(nums.begin(),nums.end());vector<long long> ans(nums.size()+1);int l=1,r=nums.size(),mid;for(int i=0;i<nums.size();i++) ans[i+1]=ans[i]+nums[i];while(l<r){mid=l+((r-l)>>1)+1;if(check(nums,ans,k,mid)) l=mid;else r=mid-1;}return l;}
};