返回介绍

solution / 2100-2199 / 2104.Sum of Subarray Ranges / README

发布于 2024-06-17 01:03:10 字数 8568 浏览 0 评论 0 收藏 0

2104. 子数组范围和

English Version

题目描述

给你一个整数数组 numsnums 中,子数组的 范围 是子数组中最大元素和最小元素的差值。

返回 nums所有 子数组范围的 _。_

子数组是数组中一个连续 非空 的元素序列。

 

示例 1:

输入:nums = [1,2,3]
输出:4
解释:nums 的 6 个子数组如下所示:
[1],范围 = 最大 - 最小 = 1 - 1 = 0 
[2],范围 = 2 - 2 = 0
[3],范围 = 3 - 3 = 0
[1,2],范围 = 2 - 1 = 1
[2,3],范围 = 3 - 2 = 1
[1,2,3],范围 = 3 - 1 = 2
所有范围的和是 0 + 0 + 0 + 1 + 1 + 2 = 4

示例 2:

输入:nums = [1,3,3]
输出:4
解释:nums 的 6 个子数组如下所示:
[1],范围 = 最大 - 最小 = 1 - 1 = 0
[3],范围 = 3 - 3 = 0
[3],范围 = 3 - 3 = 0
[1,3],范围 = 3 - 1 = 2
[3,3],范围 = 3 - 3 = 0
[1,3,3],范围 = 3 - 1 = 2
所有范围的和是 0 + 0 + 0 + 2 + 0 + 2 = 4

示例 3:

输入:nums = [4,-2,-3,4,1]
输出:59
解释:nums 中所有子数组范围的和是 59

 

提示:

  • 1 <= nums.length <= 1000
  • -109 <= nums[i] <= 109

 

进阶:你可以设计一种时间复杂度为 O(n) 的解决方案吗?

解法

方法一:暴力枚举

循环遍历 $i$,作为子数组的起始位置。对于每个 $i$,遍历每个 $j$ 作为子数组的终止位置,此过程中不断求解子数组的最大值、最小值,然后累加差值到结果 ans 中。

最后返回 ans 即可。

时间复杂度 $O(n^2)$。

class Solution:
  def subArrayRanges(self, nums: List[int]) -> int:
    ans, n = 0, len(nums)
    for i in range(n - 1):
      mi = mx = nums[i]
      for j in range(i + 1, n):
        mi = min(mi, nums[j])
        mx = max(mx, nums[j])
        ans += mx - mi
    return ans
class Solution {
  public long subArrayRanges(int[] nums) {
    long ans = 0;
    int n = nums.length;
    for (int i = 0; i < n - 1; ++i) {
      int mi = nums[i], mx = nums[i];
      for (int j = i + 1; j < n; ++j) {
        mi = Math.min(mi, nums[j]);
        mx = Math.max(mx, nums[j]);
        ans += (mx - mi);
      }
    }
    return ans;
  }
}
class Solution {
public:
  long long subArrayRanges(vector<int>& nums) {
    long long ans = 0;
    int n = nums.size();
    for (int i = 0; i < n - 1; ++i) {
      int mi = nums[i], mx = nums[i];
      for (int j = i + 1; j < n; ++j) {
        mi = min(mi, nums[j]);
        mx = max(mx, nums[j]);
        ans += (mx - mi);
      }
    }
    return ans;
  }
};
func subArrayRanges(nums []int) int64 {
  var ans int64
  n := len(nums)
  for i := 0; i < n-1; i++ {
    mi, mx := nums[i], nums[i]
    for j := i + 1; j < n; j++ {
      mi = min(mi, nums[j])
      mx = max(mx, nums[j])
      ans += (int64)(mx - mi)
    }
  }
  return ans
}
function subArrayRanges(nums: number[]): number {
  const n = nums.length;
  let res = 0;
  for (let i = 0; i < n - 1; i++) {
    let min = nums[i];
    let max = nums[i];
    for (let j = i + 1; j < n; j++) {
      min = Math.min(min, nums[j]);
      max = Math.max(max, nums[j]);
      res += max - min;
    }
  }
  return res;
}
impl Solution {
  pub fn sub_array_ranges(nums: Vec<i32>) -> i64 {
    let n = nums.len();
    let mut res: i64 = 0;
    for i in 1..n {
      let mut min = nums[i - 1];
      let mut max = nums[i - 1];
      for j in i..n {
        min = min.min(nums[j]);
        max = max.max(nums[j]);
        res += (max - min) as i64;
      }
    }
    res
  }
}

方法二:单调栈

枚举每个元素 nums[i] 作为最大值出现在了多少个子数组中,以及作为最小值出现在多少个子数组中。

其中 nums[i] 作为最大值的贡献为正,作为最小值的贡献为负。

我们以 nums[i] 作为最大值为例。找出左侧第一个比 nums[i] 大的位置 left[i],右侧第一个大于等于 nums[i] 的位置 right[i]。计算每个 nums[i] 的贡献 $(i - left[i])\times (right[i] - i)\times arr[i]$,累加得到结果。

时间复杂度 $O(n)$。

相似题目:

class Solution:
  def subArrayRanges(self, nums: List[int]) -> int:
    def f(nums):
      stk = []
      n = len(nums)
      left = [-1] * n
      right = [n] * n
      for i, v in enumerate(nums):
        while stk and nums[stk[-1]] <= v:
          stk.pop()
        if stk:
          left[i] = stk[-1]
        stk.append(i)
      stk = []
      for i in range(n - 1, -1, -1):
        while stk and nums[stk[-1]] < nums[i]:
          stk.pop()
        if stk:
          right[i] = stk[-1]
        stk.append(i)
      return sum((i - left[i]) * (right[i] - i) * v for i, v in enumerate(nums))

    mx = f(nums)
    mi = f([-v for v in nums])
    return mx + mi
class Solution {
  public long subArrayRanges(int[] nums) {
    long mx = f(nums);
    for (int i = 0; i < nums.length; ++i) {
      nums[i] *= -1;
    }
    long mi = f(nums);
    return mx + mi;
  }

  private long f(int[] nums) {
    Deque<Integer> stk = new ArrayDeque<>();
    int n = nums.length;
    int[] left = new int[n];
    int[] right = new int[n];
    Arrays.fill(left, -1);
    Arrays.fill(right, n);
    for (int i = 0; i < n; ++i) {
      while (!stk.isEmpty() && nums[stk.peek()] <= nums[i]) {
        stk.pop();
      }
      if (!stk.isEmpty()) {
        left[i] = stk.peek();
      }
      stk.push(i);
    }
    stk.clear();
    for (int i = n - 1; i >= 0; --i) {
      while (!stk.isEmpty() && nums[stk.peek()] < nums[i]) {
        stk.pop();
      }
      if (!stk.isEmpty()) {
        right[i] = stk.peek();
      }
      stk.push(i);
    }
    long s = 0;
    for (int i = 0; i < n; ++i) {
      s += (long) (i - left[i]) * (right[i] - i) * nums[i];
    }
    return s;
  }
}
class Solution {
public:
  long long subArrayRanges(vector<int>& nums) {
    long long mx = f(nums);
    for (int i = 0; i < nums.size(); ++i) nums[i] *= -1;
    long long mi = f(nums);
    return mx + mi;
  }

  long long f(vector<int>& nums) {
    stack<int> stk;
    int n = nums.size();
    vector<int> left(n, -1);
    vector<int> right(n, n);
    for (int i = 0; i < n; ++i) {
      while (!stk.empty() && nums[stk.top()] <= nums[i]) stk.pop();
      if (!stk.empty()) left[i] = stk.top();
      stk.push(i);
    }
    stk = stack<int>();
    for (int i = n - 1; i >= 0; --i) {
      while (!stk.empty() && nums[stk.top()] < nums[i]) stk.pop();
      if (!stk.empty()) right[i] = stk.top();
      stk.push(i);
    }
    long long ans = 0;
    for (int i = 0; i < n; ++i) {
      ans += (long long) (i - left[i]) * (right[i] - i) * nums[i];
    }
    return ans;
  }
};
func subArrayRanges(nums []int) int64 {
  f := func(nums []int) int64 {
    stk := []int{}
    n := len(nums)
    left := make([]int, n)
    right := make([]int, n)
    for i := range left {
      left[i] = -1
      right[i] = n
    }
    for i, v := range nums {
      for len(stk) > 0 && nums[stk[len(stk)-1]] <= v {
        stk = stk[:len(stk)-1]
      }
      if len(stk) > 0 {
        left[i] = stk[len(stk)-1]
      }
      stk = append(stk, i)
    }
    stk = []int{}
    for i := n - 1; i >= 0; i-- {
      for len(stk) > 0 && nums[stk[len(stk)-1]] < nums[i] {
        stk = stk[:len(stk)-1]
      }
      if len(stk) > 0 {
        right[i] = stk[len(stk)-1]
      }
      stk = append(stk, i)
    }
    ans := 0
    for i, v := range nums {
      ans += (i - left[i]) * (right[i] - i) * v
    }
    return int64(ans)
  }
  mx := f(nums)
  for i := range nums {
    nums[i] *= -1
  }
  mi := f(nums)
  return mx + mi
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文