LeetCode 2090. K Radius Subarray Averages【前缀和,滑动窗口,数组】中等

这篇具有很好参考价值的文章主要介绍了LeetCode 2090. K Radius Subarray Averages【前缀和,滑动窗口,数组】中等。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

给你一个下标从 0 开始的数组 nums ,数组中有 n 个整数,另给你一个整数 k 。

半径为 k 的子数组平均值 是指:nums 中一个以下标 i 为 中心 且 半径 为 k 的子数组中所有元素的平均值,即下标在 i - k 和 i + k 范围( i - k 和 i + k)内所有元素的平均值。如果在下标 i 前或后不足 k 个元素,那么 半径为 k 的子数组平均值 是 -1 。

构建并返回一个长度为 n 的数组 avgs ,其中 avgs[i] 是以下标 i 为中心的子数组的 半径为 k 的子数组平均值 。

x 个元素的 平均值 是 x 个元素相加之和除以 x ,此时使用截断式 整数除法 ,即需要去掉结果的小数部分。

  • 例如,四个元素 231 和 5 的平均值是 (2 + 3 + 1 + 5) / 4 = 11 / 4 = 2.75,截断后得到 2 。

示例 1:
LeetCode 2090. K Radius Subarray Averages【前缀和,滑动窗口,数组】中等

输入:nums = [7,4,3,9,1,8,5,2,6], k = 3
输出:[-1,-1,-1,5,4,4,-1,-1,-1]
解释:
- avg[0]、avg[1] 和 avg[2]-1 ,因为在这几个下标前的元素数量都不足 k 个。
- 中心为下标 3 且半径为 3 的子数组的元素总和是:7 + 4 + 3 + 9 + 1 + 8 + 5 = 37 。
  使用截断式 整数除法,avg[3] = 37 / 7 = 5- 中心为下标 4 的子数组,avg[4] = (4 + 3 + 9 + 1 + 8 + 5 + 2) / 7 = 4- 中心为下标 5 的子数组,avg[5] = (3 + 9 + 1 + 8 + 5 + 2 + 6) / 7 = 4- avg[6]、avg[7] 和 avg[8]-1 ,因为在这几个下标后的元素数量都不足 k 个。

示例 2:

输入:nums = [100000], k = 0
输出:[100000]
解释:
- 中心为下标 0 且半径 0 的子数组的元素总和是:100000 。
  avg[0] = 100000 / 1 = 100000

示例 3:

输入:nums = [8], k = 100000
输出:[-1]
解释:
- avg[0]-1 ,因为在下标 0 前后的元素数量均不足 k 。

提示:

  • n == nums.length
  • 1 <= n <= 10^5
  • 0 <= nums[i], k <= 10^5

解法1 前缀和

根据题目描述,只有当中心位置 i ∈ [ k , n − k − 1 ] i \in [k, n-k-1] i[k,nk1] 时,整个长度为 2 k + 1 2k+1 2k+1 的子区间才会完整地落在数组 n u m s nums nums 内部。当 i < k i<k i<k 或者 i ≥ n − k i≥n−k ink 时,对应的平均值为 − 1 -1 1

因此如果 k ≥ n − k − 1 k \geq n-k-1 knk1 2 k + 1 ≥ n 2k+1≥n 2k+1n ,答案数组中所有的元素均为 − 1 -1 1 。否则首先计算出数组 n u m s nums nums 的前缀和 s u m sum sum ,然后对 i ∈ [ k ,   n − k − 1 ] i \in [k,\ n - k - 1] i[k, nk1] 中的所有位置,利用前缀和求其 [ i − k , i + 1 ] [i -k , i +1] [ik,i+1] 的元素和、并除以 2 k + 1 2k+1 2k+1 s u m [ i + k + 1 ] − s u m [ i − k ] 2 k − 1 \dfrac{sum[i + k + 1] - sum[i - k]}{2k-1} 2k1sum[i+k+1]sum[ik]
注意,前缀和数组要用 long long ,不然会溢出。

class Solution {
    public int[] getAverages(int[] nums, int k) {
        if (k == 0) return nums;
        int n = nums.length, m = 2 * k + 1;
        int[] ans = new int[n];
        Arrays.fill(ans, -1);
        if (m > n) return ans;
        long[] sum = new long[n + 1];
        for (int i = 0; i < n; ++i) sum[i + 1] = sum[i] + nums[i];
        for (int i = k; i + k < n; ++i) ans[i] = (int)((sum[i + k + 1] - sum[i - k]) / m);
        return ans;
    }
}

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

解法2 滑动窗口

不难发现,上述做法需要 O ( n ) O(n) O(n) 的空间来存储前缀和,但实际上可以进一步优化,且只需遍历一次。

首先,先求出前 2 k + 1 2k+1 2k+1 个元素的和,放在答案数组的 a n s [ k ] ans[k] ans[k] 中。由于:
{ ans [ i − 1 ] = nums [ i − k − 1 ] + nums [ i − k ] + ⋯ + nums [ i + k − 1 ] ans [ i ] = nums [ i − k ] + ⋯ + nums [ i + k − 1 ] + nums [ i + k ] \left\{ \begin{aligned} & \textit{ans}[i - 1] && = \textit{nums}[i - k - 1] + \textit{nums}[i - k] + \cdots + \textit{nums}[i + k - 1] \\ & \textit{ans}[i] && = \textit{nums}[i - k] + \cdots + \textit{nums}[i + k - 1] + \textit{nums}[i + k] \end{aligned} \right. {ans[i1]ans[i]=nums[ik1]+nums[ik]++nums[i+k1]=nums[ik]++nums[i+k1]+nums[i+k]
​因此随后只需要通过递推式:
ans [ i ] = ans [ i − 1 ] + nums [ i + k ] − nums [ i − k − 1 ] \textit{ans}[i] = \textit{ans}[i - 1] + \textit{nums}[i + k] - \textit{nums}[i - k - 1] ans[i]=ans[i1]+nums[i+k]nums[ik1]

即可得到所有中心位置 i ∈ [ k , n − k − 1 ] i \in [k, n-k-1] i[k,nk1] 且长度为 2 k + 1 2k+1 2k+1 的子数组的和。最后将每一个和除以 2 k + 1 2k+1 2k+1 即可得到平均数。

class Solution {
    public int[] getAverages(int[] nums, int k) {
        if (k == 0) return nums;
        int n = nums.length, m = 2 * k + 1;
        int[] ans = new int[n];
        Arrays.fill(ans, -1);
        if (m > n) return ans;
        long sum = 0;
        for (int i = 0; i < m; ++i) sum += nums[i];
        for (int i = k; i + k < n; ++i) {
            if (i != k) sum += nums[i + k] - nums[i - k - 1];
            ans[i] = (int)(sum / m);
        }
        return ans;
    }
}

复杂度分析:文章来源地址https://www.toymoban.com/news/detail-500208.html

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1) ,不计算答案数组的情况下,只使用了若干辅助变量

到了这里,关于LeetCode 2090. K Radius Subarray Averages【前缀和,滑动窗口,数组】中等的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【LeetCode 算法专题突破】滑动窗口(⭐)

    学完了双指针算法,滑动窗口那肯定是逃不掉了,我个人感觉他俩就不分家,不把滑动窗口的题目好好刷上一刷我都难受 先来一道经典的滑动窗口试试水 题目链接:209. 长度最小的子数组 其实滑动窗口题目的解法都大同小异,我们基本上写几道题目,就能很好的掌握这个算

    2024年02月07日
    浏览(52)
  • LeetCode239.滑动窗口最大值

    看到这道题我就有印象, 我在剑指offer里面做过这道题,我记得当时用的是优先队列,然后我脑子里一下子就有了想法,拿优先队列作为窗口,每往右移动一步,把左边的数remove掉,把右边的数add进来,然后把队头,也就是窗口中最大的元素放入答案数组,然后就写出了如下

    2024年02月11日
    浏览(44)
  • leetcode-239-滑动窗口最大值

    题意描述: 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例: 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动

    2024年02月07日
    浏览(49)
  • LeetCode算法小抄--滑动窗口算法

    ⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计6244字,阅读大概需要3分钟 🌈更多学习内容, 欢迎👏关注👀文末我的个人微信公众号:不懂开发的程序猿 个人网站:https://jerry-jy.co/ 滑动窗口算法 思路 1、我们在字符串 S 中使用双指针中的

    2023年04月09日
    浏览(38)
  • 【滑动窗口】leetcode1004:最大连续1的个数

    最大连续1的个数  这道题要我们找最大连续1的个数,看到“连续”二字,我们要想到滑动窗口的方法。滑动窗口的研究对象是一个连续的区间,这个区间需要满足某个条件。那么本题要找的是怎样的区间呢?是一个通过翻转0后得到连续1的区间,而最多可以翻转k个字符。 故

    2024年02月11日
    浏览(39)
  • 【LeetCode热题100】【子串】滑动窗口最大值

    题目 给你一个整数数组  nums ,有一个大小为  k   的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的  k  个数字。滑动窗口每次只向右移动一位。 返回  滑动窗口中的最大值  。 示例 1: 示例 2: 提示: 1 = nums.length = 105 -104 = nums[i] = 104 1 =

    2024年01月19日
    浏览(48)
  • 剑指 Offer 59 - I. 滑动窗口的最大值 / LeetCode 239. 滑动窗口最大值(优先队列 / 单调队列)

    链接:剑指 Offer 59 - I. 滑动窗口的最大值;LeetCode 239. 滑动窗口最大值 难度:困难 下一篇:剑指 Offer 59 - II. 队列的最大值(单调队列) 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗

    2024年02月15日
    浏览(41)
  • 【滑动窗口】【map】LeetCode:76最小覆盖子串

    【二叉树】【单调双向队列】LeetCode239:滑动窗口最大值 C++算法:滑动窗口总结 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。 注意: 对于 t 中重复字符,我们寻找的子字符串中该字

    2024年02月03日
    浏览(39)
  • leetcode76. 最小覆盖子串(滑动窗口-java)

    难度 - 困难 原题链接 - 最小覆盖字串 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。 注意: 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果

    2024年02月11日
    浏览(41)
  • 算法刷题记录-双指针/滑动窗口(LeetCode)

    思路 根据题目描述,我们可以知道,如果要将某个单词定义为可扩张(stretchy),需要满足如下两个条件: 所以,我们在实现的时候,可以通过两个指针p1和p2,分别指向s和word,分别统计连续的相同字符数量c1和c2,然后再通过上述的两个条件进行判断,即:如果 则表示该单

    2024年02月09日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包