2024.2.1力扣每日一题——数字游戏

2024.02.01

题目来源

力扣每日一题;题序:LCP 24

我的题解

方法一 对顶堆

主要思想:将区间 [0,i]范围内的数字操作成相同的数字的最小操作数,等于将区间 [0,i]范围内的数字操作成它们的中位数所需要的操作数。
具体实现 :参考官方题解

分别使用两个优先队列 lower和 upper 来保存 [0,i]内的数字,同时使用 lowerSum 和 upperSum 分别保存两个优先队列的元素和,这两个优先队列中的元素满足以下两个条件:

  1. 优先队列 lower保存的任一元素都小于等于优先队列 upper保存的任一元素;
  2. 优先队列 lower 的元素数目 n l o w e r n_{lower} nlower与优先队列 upper的元素数目 n upper n_\textit{upper} nupper 满足 n upper n_\textit{upper} nupper ≤ n l o w e r n_{lower} nlower≤ n upper+1 n_\textit{upper+1} nupper+1

遍历数组 nums,假设当前遍历到元素 nums[i],考虑如何将元素 nums[i]加入优先队列,同时不违反以上条件。首先如果 lower 为空或 nums[i] 小于 lower 的最大元素,那么将 nums[i] 加入 lower,更新 lowerSum,否则将 nums[i] 加入 upper 中,更新 upperSum,此时条件 1依旧满足。然后我们需要调整优先队列的元素数目关系,以满足条件 2:

  • 如果 n l o w e r n_{lower} nlower> n upper n_\textit{upper} nupper,那么将 lower 的最大值移动到 upper,同时更新 lowerSum 和 upperSum。
  • 如果 n n l o w e r n_{lower} nlower< n upper n_\textit{upper} nupper,那么将 upper 的最小值移动到 lower,同时更新 lowerSum 和 upperSum。

那么:

  • 当 i+1 为偶数时,令中位数为 ttt,那么有 max⁡(lower)≤t≤min⁡(upper),从而 res i = ∑ j = 0 i ∣ nums [ j ] − t ∣ = upperSum − lowerSum \textit{res}i = \sum{j=0}^{i}|\textit{nums}[j] - t| = \textit{upperSum} - \textit{lowerSum} resi=∑j=0i∣nums[j]−t∣=upperSum−lowerSum。
  • 当 i+1 为奇数时,中位数 t=max⁡(lower), res i = ∑ j = 0 i ∣ nums [ j ] − t ∣ = upperSum − lowerSum + max ⁡ ( lower ) \textit{res}i = \sum{j=0}^{i}|\textit{nums}[j] - t| = \textit{upperSum} - \textit{lowerSum} + \max(\textit{lower}) resi=∑j=0i∣nums[j]−t∣=upperSum−lowerSum+max(lower)。

最后返回结果数组 res即可。
时间复杂度 :O(nlogn), 其中 n 是数组 nums 的长度。优先队列入队、出队都需要 O(log⁡n)的时间,总共需要 O(nlog⁡n) 的时间。
空间复杂度:O(n)

java 复制代码
public int[] numsGame(int[] nums) {
     int n=nums.length;
     int[] res=new int[n];
     int MOD=1000000007;
     //大顶堆
     PriorityQueue<Integer> lower=new PriorityQueue<>((a,b)->b-a);
     //小顶堆
     PriorityQueue<Integer> upper=new PriorityQueue<>((a,b)->a-b);
     long lowerSum=0;
     long upperSum=0;

     for(int i=0;i<n;i++){
         // 将区间 [0,i]范围内的数字操作成相同的数字的最小操作数,
         // 等于将区间 [0,i]范围内的数字操作成它们的中位数所需要的操作数。
         int t=nums[i]-i;
         if(lower.isEmpty()||t<=lower.peek()){
             lowerSum+=t;
             lower.offer(t);
             if(lower.size()>upper.size()+1){
                 int p=lower.poll();
                 upperSum+=p;
                 lowerSum-=p;
                 upper.offer(p);
             }
         }else{
             upperSum+=t;
             upper.offer(t);
             if(lower.size()<upper.size()){
                 int p=upper.poll();
                 upperSum-=p;
                 lowerSum+=p;
                 lower.offer(p);
             }
         }
         if((i+1)%2==0){
             res[i]=(int)((upperSum-lowerSum)%MOD);
         }else{
             res[i]=(int)((upperSum-lowerSum+lower.peek())%MOD);
         }
     }
     return res;
 }

有任何问题,欢迎评论区交流,欢迎评论区提供其它解题思路(代码),也可以点个赞支持一下作者哈😄~

相关推荐
手握风云-11 小时前
Spring AI:让大模型住进 Spring 生态(三)
java·后端·spring
深邃-12 小时前
【数据结构与算法】-二叉树(2):实现顺序结构二叉树(堆的实现),向上调整算法,向下调整算法,堆排序,TOP-K问题
数据结构·算法·二叉树·排序算法·堆排序··top-k
咸鱼2.012 小时前
【java入门到放弃】Dubbo
java·开发语言·dubbo
We་ct15 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·javascript·算法·leetcode·typescript
JAVA面经实录91718 小时前
Java企业级工程化·终极完整版背诵手册(无遗漏、全覆盖、面试+落地通用)
java·开发语言·面试
王老师青少年编程19 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮20 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说20 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
许彰午20 小时前
CacheSQL(二):主从复制——OpLog 环形缓冲区与故障自动恢复
java·数据库·缓存
wuweijianlove20 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法