• 【每日一题Day351】LC2530执行 K 次操作后的最大分数 | 原地堆化


    执行 K 次操作后的最大分数【LC2530】

    给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。你的 起始分数0

    在一步 操作 中:

    1. 选出一个满足 0 <= i < nums.length 的下标 i
    2. 将你的 分数 增加 nums[i] ,并且
    3. nums[i] 替换为 ceil(nums[i] / 3)

    返回在 恰好 执行 k 次操作后,你可能获得的最大分数。

    向上取整函数 ceil(val) 的结果是大于或等于 val 的最小整数。

    学到了

    大顶堆+贪心
    • 思路

      • 每次操作尽量选择数组中的最大值,以获得最大分数
      • 借助大顶堆存储数组元素,那么堆顶元素为每次操作的元素,每次操作完成后将 c e i l ( n u m / 3 ) ceil(num/3) ceil(num/3)放入堆中,向上取整的实现有以下三种
        • 调用API:Math.ceil(num/3.0)
        • 判断余数是否为0:num / 3 + (num % 3 == 0 ? 0 : 1)
        • 加2后再进行整除:(num + 2) / 3
    • 实现

      class Solution {
          public long maxKelements(int[] nums, int k) {
              PriorityQueue<Integer> pq = new PriorityQueue<>((o1, o2) -> o2 - o1);   
              long res = 0L;
              for (int num : nums){
                  pq.add(num);
              }
              for (int i = 0; i < k; i++){
                  int num = pq.poll();
                  res += num;
                  // pq.add(num / 3 + (num % 3 == 0 ? 0 : 1));
                  pq.add((num + 2) / 3);
                  pq.add((int)Math.ceil(num / 3.0));
      
              }
              return res;
      
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 复杂度
        • 时间复杂度: O ( n + k l o g n ) O(n+klogn) O(n+klogn)
        • 空间复杂度: O ( n ) O(n) O(n)
    堆排序:原地堆化
    • 思路:优化空间复杂度,将数组作为大顶堆

      • 大顶堆中的子节点值均不大于父节点的值,即满足 n u m s [ i ] ≥ n u m s [ 2 ∗ i + 1 ] nums[i] \ge nums[2*i+1] nums[i]nums[2i+1] n u m s [ i ] ≥ n u m s [ 2 ∗ i + 2 ] nums[i] \ge nums[2*i+2] nums[i]nums[2i+2],并且堆化后数组中最大的元素为 n u m s [ 0 ] nums[0] nums[0]
      • 堆化:将每个父节点进行下沉,判断子节点值是否不大于父节点的值
        • 如果子节点的值大于父节点的值,那么将最大子节点与父节点进行交换,直至判断到叶子节点
        • 如果子节点的值均小于父节点的值,那么不做操作
      • k k k个最大的元素:每进行一次操作,将 n u m s [ 0 ] nums[0] nums[0]变为 c e i l ( n u m s [ 0 ] / 3.0 ) ceil(nums[0]/3.0) ceil(nums[0]/3.0),然后下沉堆顶元素
    • 实现

      class Solution {
          public long maxKelements(int[] nums, int k) {
              heapify(nums); // 原地堆化(最大堆)
              long ans = 0;
              while (k-- > 0) {
                  ans += nums[0]; // 堆顶
                  nums[0] = (nums[0] + 2) / 3;
                  sink(nums, 0); // 堆化(只需要把 nums[0] 下沉)
              }
              return ans;
          }
      
          // 原地堆化(最大堆)
          // 堆化可以保证 h[0] 是堆顶元素,且 h[i] >= max(h[2*i+1], h[2*i+2])
          private void heapify(int[] h) {
              // 下标 >= h.length / 2 的元素是二叉树的叶子,无需下沉
              // 倒着遍历,从而保证 i 的左右子树一定是堆,那么 sink(h, i) 就可以把左右子树合并成一个堆
              for (int i = h.length / 2 - 1; i >= 0; i--) {
                  sink(h, i);
              }
          }
      
          // 把 h[i] 不断下沉,直到 i 的左右儿子都 <= h[i]
          private void sink(int[] h, int i) {
              int n = h.length;
              while (2 * i + 1 < n) {
                  int j = 2 * i + 1; // i 的左儿子
                  if (j + 1 < n && h[j + 1] > h[j]) { // i 的右儿子比 i 的左儿子大
                      j++;
                  }
                  if (h[j] <= h[i]) { // 说明 i 的左右儿子都 <= h[i],停止下沉
                      break;
                  }
                  swap(h, i, j); // 下沉
                  i = j;
              }
          }
      
          // 交换 h[i] 和 h[j]
          private void swap(int[] h, int i, int j) {
              int tmp = h[i];
              h[i] = h[j];
              h[j] = tmp;
          }
      }
      
      作者:灵茶山艾府
      链接:https://leetcode.cn/problems/maximal-score-after-applying-k-operations/solutions/2487446/o1-kong-jian-zuo-fa-pythonjavacgojsrust-ztx6f/
      来源:力扣(LeetCode)
      著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 复杂度
        • 时间复杂度: O ( n + k l o g n ) O(n+klogn) O(n+klogn)
        • 空间复杂度: O ( 1 ) O(1) O(1)
  • 相关阅读:
    算法篇:查找算法
    计算机毕业设计Java大学生学习时间规划平台服务端(源码+系统+mysql数据库+lw文档)
    PHP代码审计18—PHP代码审计小结
    全网最全jmeter接口测试/接口自动化测试看这篇文章就够了:跨线程组传递jmeter变量及cookie的处理
    MySQL索引和优化的理解学习
    Ubuntu16.04搭建UbertoothOne环境
    科技公司网络规划与设计
    【Python3】基础 - 基本数据类型
    《计算机视觉技术与应用》-----第五章 边缘和轮廓
    Java8从入门到精通 笔记
  • 原文地址:https://blog.csdn.net/Tikitian/article/details/133908189