第433场周赛:变长子数组求和、最多 K 个元素的子序列的最值之和、粉刷房子 Ⅳ、最多 K 个元素的子数组的最值之和

Q1、变长子数组求和

1、题目描述

给你一个长度为 n 的整数数组 nums 。对于 每个 下标 i0 <= i < n),定义对应的子数组 nums[start ... i]start = max(0, i - nums[i]))。

返回为数组中每个下标定义的子数组中所有元素的总和。

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

2、解题思路

由于子数组的起点 start 取决于 nums[i],每次计算 nums[start ... i] 的和时,我们可以借助 前缀和 来快速计算子数组的和,从而避免重复计算。

前缀和的定义

前缀和数组 prefix_sum[i] 表示 从数组开始到索引 i-1 的元素之和,即:

prefix_sum [ i ] = ∑ j = 0 i − 1 nums [ j ] \text{prefix\_sum}[i] = \sum_{j=0}^{i-1} \text{nums}[j] prefix_sum[i]=j=0i1nums[j]

则某个区间 [start, i] 的子数组和可以通过前缀和快速计算:

∑ j = start i nums [ j ] = prefix_sum [ i + 1 ] − prefix_sum [ start ] \sum_{j=\text{start}}^{i} \text{nums}[j] = \text{prefix\_sum}[i+1] - \text{prefix\_sum}[\text{start}] j=startinums[j]=prefix_sum[i+1]prefix_sum[start]

这样,我们可以在 O(1) 时间内计算每个 i 对应的子数组的和,而不会重复累加相同的元素,整体时间复杂度 降为 O(n)

3、代码实现

class Solution {
public:int subarraySum(vector<int>& nums) {int n = nums.size();vector<int> prefix_sum(n + 1, 0); // 前缀和数组, prefix_sum[i] 表示 nums[0] 到 nums[i-1] 的和// 计算前缀和for (int i = 0; i < n; ++i) {prefix_sum[i + 1] = prefix_sum[i] + nums[i];}int result = 0; // 存储所有子数组的元素和for (int i = 0; i < n; ++i) {int start = max(0, i - nums[i]); // 计算子数组的起始位置result += prefix_sum[i + 1] - prefix_sum[start]; // 使用前缀和计算子数组和}return result;}
};

在这里插入图片描述

4、复杂度分析

前缀和计算 需要 O(n) 的时间。

子数组求和 通过前缀和的方式优化,每次 O(1),整体仍然是 O(n)

空间复杂度:使用额外的前缀和数组 O(n),因此 空间复杂度 O(n)


Q2、最多 K 个元素的子序列的最值之和

1、题目描述

给你一个整数数组 nums 和一个正整数 k,返回所有长度最多为 k子序列最大值最小值 之和的总和。

非空子序列 是指从另一个数组中删除一些或不删除任何元素(且不改变剩余元素的顺序)得到的数组。

由于答案可能非常大,请返回对 109 + 7 取余数的结果。

2、解题思路

思路:数学 + 组合数优化计算

(1) 排序数组,便于计算最小值和最大值

假设 nums 排序后为:nums = [a1, a2, ..., an]

  • nums[i] 作为子序列的 最小值 时,其前面的 i 个元素可以自由选择(或不选),最大长度不超过 k
  • nums[i] 作为子序列的 最大值 时,其后面的 n - i - 1 个元素可以自由选择,最大长度不超过 k

(2) 计算 nums[i] 作为最小值的贡献

nums[i] 作为 最小值 时,所有子序列来自 [i, n-1] 的元素。
对于长度 ≤ k 的子序列,其前 i 个元素可以选,也可以不选,形成的子序列数为:

∑ j = 0 min ⁡ ( k , i ) C ( i , j ) \sum_{j=0}^{\min(k, i)} C(i, j) j=0min(k,i)C(i,j)

其中 C(i, j) 是组合数,即:

C ( i , j ) = i ! j ! ( i − j ) ! C(i, j) = \frac{i!}{j! (i-j)!} C(i,j)=j!(ij)!i!

(3) 计算 nums[i] 作为最大值的贡献

由于 nums[i] 作为最大值时,其对称位置 nums[n - 1 - i] 作为最小值,因此我们直接计算 nums[i]nums[n - 1 - i] 的贡献之和。

(4) 预计算阶乘与逆元,加速组合数计算

由于 C(n, m) 的计算涉及 阶乘求逆,直接计算 C(n, m) 可能会超时,因此我们使用 预计算 + 逆元 快速求解:

  • 预计算 阶乘 factorial[i] = i! % MOD
  • 预计算 阶乘逆元 invFactorial[i] = (i!)^{-1} % MOD
  • 通过 快速幂求逆元 (Fermat 小定理)

3、代码实现

const int MOD = 1000000007;
const int MAX_N = 100000;long long factorial[MAX_N]; // 存储阶乘 F[i] = i!
long long invFactorial[MAX_N];long long powerMod(long long x, int n) {long long res = 1;while (n > 0) {if (n & 1) // 如果 n 是奇数{res = res * x % MOD;}x = x * x % MOD;n >>= 1; // n 右移, 相当于除以 2}return res;
}// 预处理阶乘及其逆元
void precomputeFactorial() {factorial[0] = 1;for (int i = 1; i < MAX_N; ++i) {factorial[i] = factorial[i - 1] * i % MOD;}// 计算 (MAX_N - 1)! 的逆元invFactorial[MAX_N - 1] = powerMod(factorial[MAX_N - 1], MOD - 2);// 计算所有 (i!)^-1for (int i = MAX_N - 2; i >= 0; --i) {invFactorial[i] = invFactorial[i + 1] * (i + 1) % MOD;}
}// 计算组合数 C(n, m) = n! / (m! * (n-m)!)
long long comb(int n, int m) {if (m > n || m < 0) {return 0;}return factorial[n] * invFactorial[m] % MOD * invFactorial[n - m] % MOD;
}// 预处理组合数
auto _ = (precomputeFactorial(), 0);class Solution {
public:int minMaxSums(vector<int>& nums, int k) {sort(nums.begin(), nums.end()); // 先排序, 方便计算 min/maxint n = nums.size();long long totalSum = 0;// 计算所有长度 <= k 的子序列贡献for (int i = 0; i < n; ++i) {long long subsetCount = 0;// 计算 nums[i] 作为最小值的贡献for (int j = 0; j < min(k, i + 1); ++j) {subsetCount = (subsetCount + comb(i, j)) % MOD;}// 计算 nums[i] 作为最大值的对称贡献totalSum = (totalSum + subsetCount * (nums[i] + nums[n - 1 - i]) % MOD) % MOD;}return totalSum;}
};

在这里插入图片描述

4、复杂度分析

排序O(n log n)

预处理阶乘和逆元O(n)

计算所有 C(i, j):最坏情况下 O(nk),但一般远小于 O(n^2)

最终复杂度O(n log n + n + nk) ≈ O(n log n + nk)


Q3、粉刷房子 Ⅳ

1、题目描述

给你一个 偶数 整数 n,表示沿直线排列的房屋数量,以及一个大小为 n x 3 的二维数组 cost,其中 cost[i][j] 表示将第 i 个房屋涂成颜色 j + 1 的成本。

如果房屋满足以下条件,则认为它们看起来 漂亮

  • 不存在 两个 涂成相同颜色的相邻房屋。
  • 距离行两端 等距 的房屋不能涂成相同的颜色。例如,如果 n = 6,则位置 (0, 5)(1, 4)(2, 3) 的房屋被认为是等距的。

返回使房屋看起来 漂亮最低 涂色成本。

2、解题思路

题目转化

由于房屋成对对称,我们可以将问题转换为处理 n/2 对房屋:

  • (0, n-1), (1, n-2), …, (n/2 - 1, n/2)

定义 dp[i][prevLeft][prevRight]

  • 表示前 i+1 对房屋(0i),上一对房屋 (i-1) 选择了 prevLeftprevRight 颜色时,符合要求的最低涂色成本

动态规划状态定义

  • dp[i][leftColor][rightColor]:表示涂完第 i 对房屋,并且当前这对房屋的左房屋leftColor右房屋rightColor 的最小成本。
  • 递推关系:
    • 枚举上一个房屋对 (i-1) 的颜色 prevLeftprevRight
    • 确保 leftColor ≠ prevLeftrightColor ≠ prevRight,并且 leftColor ≠ rightColor
    • 计算新的 dp[i][leftColor][rightColor] 的最小值。

3、代码实现

class Solution {
public:long long minCost(int n, vector<vector<int>>& cost) {// 动态规划数组 dp[i][prevLeft][prevRight]vector<vector<vector<long long>>> dp(n / 2 + 1, vector<vector<long long>>(3, vector<long long>(3, LLONG_MAX)));// 初始化 dp[0], 即第 0 对房屋的所有可能涂色情况for (int leftColor = 0; leftColor < 3; leftColor++) {for (int rightColor = 0; rightColor < 3; rightColor++) {// 初始状态不能相同if (leftColor != rightColor) {dp[0][leftColor][rightColor] = cost[0][leftColor] + cost[n - 1][rightColor];}}}// 动态规划计算所有房屋对的最小涂色成本for (int i = 1; i < n / 2; i++) {for (int prevLeft = 0; prevLeft < 3; prevLeft++) {for (int prevRight = 0; prevRight < 3; prevRight++) {// 如果上一对房屋 (i-1) 没有有效涂色方案, 跳过if (dp[i - 1][prevLeft][prevRight] == LLONG_MAX) {continue;}for (int leftColor = 0; leftColor < 3; leftColor++) {// 左房颜色不能和上一对左房相同if (leftColor == prevLeft) {continue;}for (int rightColor = 0; rightColor < 3; rightColor++) {// 右房颜色不能和上一对右房或左房相同if (rightColor == prevRight || rightColor == leftColor) {continue;}// 计算当前房屋对的成本long long currCost = cost[i][leftColor] + cost[n - 1 - i][rightColor];// 更新最小成本dp[i][leftColor][rightColor] = min(dp[i][leftColor][rightColor], dp[i - 1][prevLeft][prevRight] + currCost);}}}}}// 计算最终答案: 取最后一对房屋的所有可能涂色方案中的最小值long long minCost = LLONG_MAX;for (int leftColor = 0; leftColor < 3; leftColor++) {for (int rightColor = 0; rightColor < 3; rightColor++) {minCost = min(minCost, dp[n / 2 - 1][leftColor][rightColor]);}}return minCost;}
};

在这里插入图片描述

4、复杂度分析

  • 状态数量O(n/2 * 3 * 3) ≈ O(n)
  • 转移复杂度:每个 dp[i] 依赖于 dp[i-1],共 O(3^4) = O(81) 种情况。

总体复杂度: O ( n × 81 ) = O ( n ) O(n \times 81) = O(n) O(n×81)=O(n) 对于 n ≤ 10^4 仍然可以接受。


Q4、最多 K 个元素的子数组的最值之和

1、题目描述

给你一个整数数组 nums 和一个 整数 k 。 返回 最多k 个元素的所有子数组的 最大最小 元素之和。

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

2、解题思路

我们采用 单调栈数学公式 进行高效计算:

  1. 如何计算所有子数组的最小值贡献?
    • 使用单调 递增 栈,维护子数组的最小值,并计算它们的贡献。
    • 当栈顶元素比当前元素 大于等于 时,说明它无法继续作为最小值,弹出栈并计算贡献。
    • 贡献计算的核心在于,一个元素在多少个子数组中作为最小值
  2. 如何计算所有子数组的最大值贡献?
    • 只需 取反 nums 数组,将最大值问题转化为最小值问题,再计算一次即可。
  3. 如何计算子数组个数?
    • 数学公式:
      设子数组的长度为 m,若 m ≤ k,则该长度的所有子数组个数为: m(m+1)2\frac{m(m+1)}{2}2m(m+1)​ 若 m > k,则受 k 限制,其计算公式如下: (m×2−k+1)×k2\frac{(m \times 2 - k + 1) \times k}{2}2(m×2−k+1)×k​
    • 这个公式的推导基于滑动窗口思想,保证所有长度最多为 k 的子数组都被正确计算。

3、代码实现

class Solution {
public:long long minMaxSubarraySum(vector<int>& nums, int k) {// 计算长度为 m 的所有子数组的个数 (最多 k 个元素)auto countSubarrays = [&](int m) -> long long {return (m > k) ? 1LL * (m * 2 - k + 1) * k / 2 : 1LL * (m + 1) * m / 2;};// 计算所有子数组的最小值贡献auto sumSubarrayMins = [&](vector<int>& arr) -> long long {long long totalSum = 0;stack<int> st;st.push(-1); // 哨兵,方便计算边界for (int r = 0; r < arr.size(); r++) {// 维护单调递增栈, 保证栈中元素递增while (st.size() > 1 && arr[st.top()] >= arr[r]) {int i = st.top(); // 取出栈顶元素st.pop();int l = st.top(); // 栈顶元素的左边界// 计算该元素 arr[i] 作为最小值的贡献long long count = countSubarrays(r - l - 1) - countSubarrays(i - l - 1) - countSubarrays(r - i - 1);totalSum += arr[i] * count;}st.push(r);}return totalSum;};// 在 nums 末尾添加一个特殊值, 使得所有元素都能出栈计算贡献nums.push_back(INT_MIN / 2);long long ret = sumSubarrayMins(nums);// 取反 nums, 将最大值问题转化为最小值问题for (int& num : nums) {num = -num;}nums.back() *= -1; // 修正末尾特殊值ret -= sumSubarrayMins(nums);return ret;}
};

在这里插入图片描述

4、复杂度分析

单调栈的时间复杂度:

  • 每个元素 仅入栈一次,出栈一次,所以时间复杂度为 O(n)

两次计算 (最小值 & 最大值):

  • sumSubarrayMins(nums) 执行两次,总时间复杂度 O(n)

额外空间复杂度:

  • 只用了一个栈 st,额外空间复杂度 O(n)


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/15369.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS 伪类(Pseudo-classes)的详细介绍

CSS 伪类详解与示例 在日常的前端开发中&#xff0c;CSS 伪类可以帮助我们非常精准地选择元素或其特定状态&#xff0c;从而达到丰富页面表现的目的。本文将详细介绍以下伪类的使用&#xff1a; 表单相关伪类 :checked、:disabled、:enabled、:in-range、:invalid、:optional、…

Centos挂载镜像制作本地yum源,并补装图形界面

内网环境centos7.9安装图形页面内网环境制作本地yum源 上传镜像到服务器目录 创建目录并挂载镜像 #创建目录 cd /mnt/ mkdir iso#挂载 mount -o loop ./CentOS-7-x86_64-DVD-2009.iso ./iso #前面镜像所在目录&#xff0c;后面所挂载得目录#检查 [rootlocalhost mnt]# df -h…

大模型推理——MLA实现方案

1.整体流程 先上一张图来整体理解下MLA的计算过程 2.实现代码 import math import torch import torch.nn as nn# rms归一化 class RMSNorm(nn.Module):""""""def __init__(self, hidden_size, eps1e-6):super().__init__()self.weight nn.Pa…

Python截图轻量化工具

一、兼容局限性 这是用Python做的截图工具&#xff0c;不过由于使用了ctypes调用了Windows的API, 同时访问了Windows中"C:/Windows/Cursors/"中的.cur光标样式文件, 这个工具只适用于Windows环境&#xff1b; 如果要提升其跨平台性的话&#xff0c;需要考虑替换cty…

链表(LinkedList) 1

上期内容我们讲述了顺序表&#xff0c;知道了顺序表的底层是一段连续的空间进行存储(数组)&#xff0c;在插入元素或者删除元素需要将顺序表中的元素整体移动&#xff0c;时间复杂度是O(n)&#xff0c;效率比较低。因此&#xff0c;在Java的集合结构中又引入了链表来解决这一问…

SpringAI系列 - 使用LangGPT编写高质量的Prompt

目录 一、LangGPT —— 人人都可编写高质量 Prompt二、快速上手2.1 诗人 三、Role 模板3.1 Role 模板3.2 Role 模板使用步骤3.3 更多例子 四、高级用法4.1 变量4.2 命令4.3 Reminder4.4 条件语句4.5 Json or Yaml 方便程序开发 一、LangGPT —— 人人都可编写高质量 Prompt La…

jupyterLab插件开发

jupyter lab安装、配置&#xff1a; jupyter lab安装、配置教程_容器里装jupyterlab-CSDN博客 『Linux笔记』服务器搭建神器JupyterLab_linux_布衣小张-腾讯云开发者社区 Jupyter Lab | 安装、配置、插件推荐、多用户使用教程-腾讯云开发者社区-腾讯云 jupyterLab插件开发教…

使用LLaMA Factory踩坑记录

前置条件&#xff1a;电脑显卡RTX 4080 问题&#xff1a;LLaMA-Factory在运行的时候&#xff0c;弹出未检测到CUDA的报错信息 结论&#xff1a;出现了以上的报错&#xff0c;主要可以归结于以下两个方面&#xff1a; 1、没有安装GPU版本的pytorch&#xff0c;下载的是CPU版本…

『Apisix进阶篇』结合Consul作服务发现实战演练

文章目录 一、引言二、APISIX与Consul集成2.1 环境准备2.2 配置Consul服务发现2.2.1 修改APISIX配置文件2.2.2 重启APISIX 2.3 在路由中使用Consul服务发现2.3.1 创建路由2.3.2 验证路由 2.4 高级配置2.4.1 服务过滤2.4.2 多数据中心支持 三、总结 &#x1f4e3;读完这篇文章里…

SpringBoot速成(八)登录实战:未登录不能访问 P5-P8

1.登录 package com.itheima.springbootconfigfile.controller;import com.itheima.springbootconfigfile.pojo.Result; import com.itheima.springbootconfigfile.pojo.User; import com.itheima.springbootconfigfile.service.UserService;import com.itheima.springbootco…

对接DeepSeek

其实&#xff0c;整个对接过程很简单&#xff0c;就四步&#xff0c;获取key&#xff0c;找到接口文档&#xff0c;接口测试&#xff0c;代码对接。 获取 KEY https://platform.deepseek.com/transactions 直接付款就是了&#xff08;现在官网暂停充值2025年2月7日&#xff0…

ASP.NET Core JWT

目录 Session的缺点 JWT&#xff08;Json Web Token&#xff09; 优点&#xff1a; 登录流程 JWT的基本使用 生成JWT 解码JWT 用JwtSecurityTokenHandler对JWT解码 注意 Session的缺点 对于分布式集群环境&#xff0c;Session数据保存在服务器内存中就不合适了&#…

【MySQL】深度学习数据库开发技术:使用CC++语言访问数据库

**前言&#xff1a;**本节内容介绍使用C/C访问数据库&#xff0c; 包括对数据库的增删查改操作。 主要是学习一些接口的调用&#xff0c; 废话不多说&#xff0c; 开始我们的学习吧&#xff01; ps:本节内容比较容易&#xff0c; 友友们放心观看哦&#xff01; 目录 准备mysql…

postgreSQL16.6源码安装

1.获取源码 从PostgreSQL: File Browser获取tar.bz2或者tar.gz源码 2.解压 tar xf postgresql-version.tar.bz2 roothwz-VMware-Virtual-Platform:/usr/local# tar xf postgresql-16.6.tar.bz2 roothwz-VMware-Virtual-Platform:/usr/local# ll 总计 24324 drwxr-xr-x 12 ro…

音频进阶学习十一——离散傅里叶级数DFS

文章目录 前言一、傅里叶级数1.定义2.周期信号序列3.表达式DFSIDFS参数含义 4.DFS公式解析1&#xff09;右边解析 T T T、 f f f、 ω \omega ω的关系求和公式N的释义求和公式K的释义 e j ( − 2 π k n N ) e^{j(\frac{-2\pi kn}{N})} ej(N−2πkn​)的释义 ∑ n 0 N − 1 e…

【kafka系列】Topic 与 Partition

Kafka 的 Topic&#xff08;主题&#xff09; 和 Partition&#xff08;分区&#xff09; 是数据组织的核心概念&#xff0c;它们的映射关系及在 Broker 上的分布直接影响 Kafka 的性能、扩展性和容错能力。以下是详细解析&#xff1a; 一、Topic 与 Partition 的映射关系 Top…

卷积神经网络CNN如何处理语音信号

卷积神经网络&#xff08;CNN&#xff09;在处理语音数据时通常不直接处理原始的一维波形信号&#xff0c;而是处理经过预处理的二维语音特征图。以下是CNN处理语音数据时的常见数据类型和步骤&#xff1a; 1. 语音信号预处理 语音信号通常是一维的时间序列&#xff08;波形信…

【MQ】Spring3 中 RabbitMQ 的使用与常见场景

一、初识 MQ 传统的单体架构&#xff0c;分布式架构的同步调用里&#xff0c;无论是方法调用&#xff0c;还是 OpenFeign 难免会有以下问题&#xff1a; 扩展性差&#xff08;高耦合&#xff0c;需要依赖对应的服务&#xff0c;同样的事件&#xff0c;不断有新需求&#xff0…

GB/T 43698-2024 《网络安全技术 软件供应链安全要求》标准解读

一、43698-2024标准图解 https://mmbiz.qpic.cn/sz_mmbiz_png/rwcfRwCticvgeBPR8TWIPywUP8nGp4IMFwwrxAHMZ9Enfp3wibNxnfichT5zs7rh2FxTZWMxz0je9TZSqQ0lNZ7lQ/640?wx_fmtpng&fromappmsg 标准在线预览&#xff1a; 国家标准|GB/T 43698-2024 相关标准&#xff1a; &a…

Linux系统-centos防火墙firewalld详解

Linux系统-centos7.6 防火墙firewalld详解 1 firewalld了解 CentOS 7.6默认的防火墙管理工具是firewalld&#xff0c;它取代了之前的iptables防火墙。firewalld属于典型的包过滤防火墙或称之为网络层防火墙&#xff0c;与iptables一样&#xff0c;都是用来管理防火墙的工具&a…