[路飞]leetcode-1508.子数组和排序后的区间和

148 阅读1分钟

给你一个数组 nums ,它包含 n 个正整数。你需要计算所有非空连续子数组的和,并将它们按升序排序,得到一个新的包含 n * (n + 1) / 2 个数字的数组。

请你返回在新数组中下标为 **left 到 right  (下标从 1 开始) 的所有数字和(包括左右端点)。由于答案可能很大,请你将它对 10^9 + 7 取模后返回。力扣原文

示例 1:

输入: nums = [1,2,3,4], n = 4, left = 1, right = 5
输出: 13 
解释: 所有的子数组和为 1, 3, 6, 10, 2, 5, 9, 3, 7, 4 。将它们升序排序后,我们得到新的数组 [1, 2, 3, 3, 4, 5, 6, 7, 9, 10] 。下标从 le = 1 到 ri = 5 的和为 1 + 2 + 3 + 3 + 4 = 13

示例 2:

输入: nums = [1,2,3,4], n = 4, left = 3, right = 4
输出: 6
解释: 给定数组与示例 1 一样,所以新数组为 [1, 2, 3, 3, 4, 5, 6, 7, 9, 10] 。下标从 le = 3 到 ri = 4 的和为 3 + 3 = 6

示例 3:

输入: nums = [1,2,3,4], n = 4, left = 1, right = 10
输出: 50

解题:

class Heap {
  constructor(cmp, max) {
    const defaultCmp = (a, b) => a > b;
    this.list = [];
    //默认大顶堆
    this.cmp = cmp || defaultCmp;
    this.max = max || null;
  }
  size() {
    return this.list.length;
  }
  top() {
    return this.list.length === 0 ? null : this.list[0];
  }
  push(val) {
    this.list.push(val);
    if (this.size() > 1) {
      this.bubbleUp(this.size() - 1);
    }
    if (this.max !== null && this.size() > this.max) this.pop();
  }
  pop() {
    if (!this.size()) {
      return null;
    } else if (this.size() === 1) {
      return this.list.pop();
    }
    const top = this.list[0];
    this.list[0] = this.list.pop();
    this.bubbleDown(0);
    return top;
  }
  //向上调整
  bubbleUp(idx) {
    while (idx) {
      let parentIdx = (idx - 1) >> 1;
      if (this.cmp(this.list[parentIdx], this.list[idx])) {
        this.swap(idx, parentIdx);
        idx = parentIdx;
      } else {
        break;
      }
    }
  }
  //向下调整
  bubbleDown() {
    let cur = 0,
      leftIdx = 1,
      rightIdx = 2,
      size = this.size();
    while (
      (leftIdx < size && this.cmp(this.list[cur], this.list[leftIdx])) ||
      (rightIdx < size && this.cmp(this.list[cur], this.list[rightIdx]))
    ) {
      if (
        rightIdx < size &&
        this.cmp(this.list[leftIdx], this.list[rightIdx])
      ) {
        this.swap(rightIdx, cur);
        cur = rightIdx;
      } else {
        this.swap(leftIdx, cur);
        cur = leftIdx;
      }
      (leftIdx = cur * 2 + 1), (rightIdx = cur * 2 + 2);
    }
  }
  // 交换
  swap(i, j) {
    [this.list[i], this.list[j]] = [this.list[j], this.list[i]];
  }
}
var rangeSum = function (nums, n, left, right) {
    const heap=new Heap((a,b)=>a.sum>b.sum)
    for (let i = 0; i < n; i++) {
        heap.push({i,j:i,sum:nums[i]})
        
    }
    let result=0
    for (let i = 1; i <= right; i++) {
        let min=heap.pop()
        if(i>=left){
            result+=min.sum

        }
        if(min.j<n-1){
            heap.push(
                {
                    i:min.i,
                    j:min.j+1,
                    sum:min.sum + nums[min.j + 1]
                }
            )
        }
    }
    return result%1000000007
};