LeetCode 3165.不包含相邻元素的子序列的最大和:单点修改的线段树(动态规划)
【LetMeFly】3165.不包含相邻元素的子序列的最大和:单点修改的线段树(动态规划)
力扣题目链接:https://leetcode.cn/problems/maximum-sum-of-subsequence-with-non-adjacent-elements/
给你一个整数数组 nums 和一个二维数组 queries,其中 queries[i] = [posi, xi]。
对于每个查询 i,首先将 nums[posi] 设置为 xi,然后计算查询 i 的答案,该答案为 nums 中 不包含相邻元素 的 子序列 的 最大 和。
返回所有查询的答案之和。
由于最终答案可能非常大,返回其对 109 + 7 取余 的结果。
子序列 是指从另一个数组中删除一些或不删除元素而不改变剩余元素顺序得到的数组。
示例 1:
输入:nums = [3,5,9], queries = [[1,-2],[0,-3]]
输出:21
解释:
执行第 1 个查询后,nums = [3,-2,9],不包含相邻元素的子序列的最大和为 3 + 9 = 12。
执行第 2 个查询后,nums = [-3,-2,9],不包含相邻元素的子序列的最大和为 9 。
示例 2:
输入:nums = [0,-1], queries = [[0,-5]]
输出:0
解释:
执行第 1 个查询后,nums = [-5,-1],不包含相邻元素的子序列的最大和为 0(选择空子序列)。
提示:
1 <= nums.length <= 5 * 104-105 <= nums[i] <= 1051 <= queries.length <= 5 * 104queries[i] == [posi, xi]0 <= posi <= nums.length - 1-105 <= xi <= 105
解题方法:线段树 + DP
对于单次操作,我们可以使用分治的方法来求解。对于一个子区间,我们比较关注的有:区间第一个元素是否被选取、区间最后一个元素是否被选取。也就是说,对于一个子区间,一共有以下4种情况:
- 开头一定不选,结尾一定不选,记为 f 00 f00 f00
- 开头一定不选,结尾可选(也可不选),记为 f 01 f01 f01
- 开头可选(也可不选),结尾一定不选,记为 f 10 f10 f10
- 开头可选(也可不选),结尾可选(也可不选),记为 f 11 f11 f11
那么对于区间 [ l e f t , r i g h t ] [left, right] [left,right],如何进行分治操作呢?
-
如果 l e f t = = r i g h t left==right left==right,那么这个区间就只有一个元素,这个区间的 f 00 = f 01 = f 10 = 0 f00=f01=f10=0 f00=f01=f10=0, f 11 = max ( 0 , n u m s [ l e f t ] ) f11=\max(0, nums[left]) f11=max(0,nums[left])。
-
否则,令 m i d = ⌊ l e f t + r i g h t 2 ⌋ mid = \lfloor\frac{left+right}{2}\rfloor mid=⌊2left+right⌋,递归计算 [ l e f t , m i d ] [left, mid] [left,mid]和 [ m i d + 1 , r i g h t ] [mid + 1, right] [mid+1,right]两个子区间的4个值并汇总得到这个区间的4个值。
假设左区间为 p p p,右区间为 q q q,则汇总方式为:
- f 00 = max ( f p 00 + f q 10 , f p 01 + f q 00 ) f00 = \max(f_p00+f_q10, f_p01+f_q00) f00=max(fp00+fq10,fp01+fq00)
- f 01 = max ( f p 00 + f q 11 , f p 01 + f q 01 ) f01 = \max(f_p00+f_q11, f_p01+f_q01) f01=max(fp00+fq11,fp01+fq01)
- f 10 = max ( f p 10 + f q 10 , f p 11 + f q 00 ) f10 = \max(f_p10+f_q10, f_p11+f_q00) f10=max(fp10+fq10,fp11+fq00)
- f 11 = max ( f p 10 + f q 11 , f p 11 + f q 01 ) f11 = \max(f_p10+f_q11, f_p11+f_q01) f11=max(fp10+fq11,fp11+fq01)
那么如何应对 l e n ( q u e r i e s ) len(queries) len(queries)次的修改呢?那就需要引入线段树了。
- 对于修改操作,使用线段树实现单点修改,线段树的每个节点维护对应区间的4个值
- 对于查询操作,线段树根节点(整个区间)的 f 11 f11 f11记为所求
时空复杂度分析
- 时间复杂度 O ( n + q log n ) O(n+q\log n) O(n+qlogn),其中 n = l e n ( n u m s ) n=len(nums) n=len(nums), q = l e n ( q u e r i e s ) q=len(queries) q=len(queries)
- 空间复杂度 O ( n ) O(n) O(n)
AC代码
C++
const unsigned int mod = 1e9 + 7;class Solution {
private:vector<array<unsigned int, 4>> tree; // 00, 01, 10, 11void maintain(int index) {int leftIndex = 2 * index + 1;int rightIndex = 2 * index + 2;tree[index] = {max(tree[leftIndex][1] + tree[rightIndex][0], tree[leftIndex][0] + tree[rightIndex][2]),max(tree[leftIndex][0] + tree[rightIndex][3], tree[leftIndex][1] + tree[rightIndex][1]),max(tree[leftIndex][2] + tree[rightIndex][2], tree[leftIndex][3] + tree[rightIndex][0]),max(tree[leftIndex][2] + tree[rightIndex][3], tree[leftIndex][3] + tree[rightIndex][1])};}void buildTree(vector<int>& nums, int index, int left, int right) {if (left == right) {tree[index] = {0, 0, 0, (unsigned int)max(nums[left], 0)};return;}int mid = (left + right) / 2;buildTree(nums, 2 * index + 1, left, mid);buildTree(nums, 2 * index + 2, mid + 1, right);maintain(index);}void update(int index, int left, int right, int modifiedI, int val) {if (left == right) {tree[index][3] = max(0, val);return;}int mid = (left + right) / 2;if (modifiedI <= mid) {update(2 * index + 1, left, mid, modifiedI, val);} else {update(2 * index + 2, mid + 1, right, modifiedI, val);}maintain(index);}
public:int maximumSumSubsequence(vector<int>& nums, vector<vector<int>>& queries) {tree.resize(nums.size() * 4);buildTree(nums, 0, 0, nums.size() - 1);unsigned int ans = 0;for (vector<int>& query : queries) {update(0, 0, nums.size() - 1, query[0], query[1]);ans = (ans + tree[0][3]) % mod;}return ans;}
};
Python
from typing import ListMOD = 1_000_000_007
class Solution:def maintain(self, index: int) -> None:leftNode = self.tree[2 * index + 1]rightNode = self.tree[2 * index + 2]self.tree[index] = [max(leftNode[0] + rightNode[2], leftNode[1] + rightNode[0]),max(leftNode[0] + rightNode[3], leftNode[1] + rightNode[1]),max(leftNode[2] + rightNode[2], leftNode[3] + rightNode[0]),max(leftNode[2] + rightNode[3], leftNode[3] + rightNode[1])]def build(self, index: int, left: int, right: int) -> None:if left == right:self.tree[index][3] = self.nums[left]returnmid = (left + right) >> 1self.build(2 * index + 1, left, mid)self.build(2 * index + 2, mid + 1, right)self.maintain(index)def update(self, index: int, left: int, right: int, modifiedI: int, val: int) -> None:if left == right:self.tree[index][3] = max(0, val)returnmid = (left + right) >> 1if modifiedI <= mid:self.update(2 * index + 1, left, mid, modifiedI, val)else:self.update(2 * index + 2, mid + 1, right, modifiedI, val)self.maintain(index)def maximumSumSubsequence(self, nums: List[int], queries: List[List[int]]) -> int:self.tree = [[0, 0, 0, 0] for _ in range(len(nums) * 4)] # 00, 01, 10, 11self.nums = numsself.build(0, 0, len(nums) - 1)ans = 0for q, v in queries:self.update(0, 0, len(nums) - 1, q, v)ans = (ans + self.tree[0][3]) % MODreturn ans
Java
class Solution {private long[][] tree; // 诶,如果不是long的话会有两组数据无法通过private final int mod = 1000000007;private void maintain(int index) {long[] leftNode = tree[2 * index + 1];long[] rightNode = tree[2 * index + 2];tree[index][0] = Math.max(leftNode[0] + rightNode[2], leftNode[1] + rightNode[0]);tree[index][1] = Math.max(leftNode[0] + rightNode[3], leftNode[1] + rightNode[1]);tree[index][2] = Math.max(leftNode[2] + rightNode[2], leftNode[3] + rightNode[0]);tree[index][3] = Math.max(leftNode[2] + rightNode[3], leftNode[3] + rightNode[1]);}private void build(int[] nums, int index, int left, int right) {if (left == right) {tree[index][3] = Math.max(0, nums[left]);return;}int mid = (left + right) / 2;build(nums, 2 * index + 1, left, mid);build(nums, 2 * index + 2, mid + 1, right);maintain(index);}private void update(int index, int left, int right, int modifiedI, int val) {if (left == right) {tree[index][3] = Math.max(0, val);return;}int mid = (left + right) / 2;if (modifiedI <= mid) {update(2 * index + 1, left, mid, modifiedI, val);} else {update(2 * index + 2, mid + 1, right, modifiedI, val);}maintain(index);}public int maximumSumSubsequence(int[] nums, int[][] queries) {tree = new long[4 * nums.length][4]; // 00, 01, 10, 11build(nums, 0, 0, nums.length - 1);long ans = 0;for (int[] query : queries) {update(0, 0, nums.length - 1, query[0], query[1]);ans = (ans + tree[0][3]) % mod;}return (int)ans;}
}
Go
package maintype data struct {_00 int_01 int_10 int_11 int
}type seg []datafunc max(a int, b int) int {if a >= b {return a}return b
}func maintain(tree seg, index int) {leftNode := tree[index * 2 + 1]rightNode := tree[index * 2 + 2]tree[index] = data{max(leftNode._00 + rightNode._10, leftNode._01 + rightNode._00),max(leftNode._00 + rightNode._11, leftNode._01 + rightNode._01),max(leftNode._10 + rightNode._10, leftNode._11 + rightNode._00),max(leftNode._10 + rightNode._11, leftNode._11 + rightNode._01),}
}func build(tree seg, nums []int, index int, left int, right int) {if left == right {tree[index]._11 = max(0, nums[left])return}mid := (left + right) >> 1build(tree, nums, 2 * index + 1, left, mid)build(tree, nums, 2 * index + 2, mid + 1, right)maintain(tree, index)
}func update(tree seg, index int, left int, right int, modified int, val int) {if left == right {tree[index]._11 = max(0, val)return}mid := (left + right) >> 1if modified <= mid {update(tree, 2 * index + 1, left, mid, modified, val)} else {update(tree, 2 * index + 2, mid + 1, right, modified, val)}maintain(tree, index)
}func maximumSumSubsequence(nums []int, queries [][]int) int {tree := make(seg, len(nums) * 4)build(tree, nums, 0, 0, len(nums) - 1)ans := 0for _, query := range queries {update(tree, 0, 0, len(nums) - 1, query[0], query[1])ans = (ans + tree[0]._11) % 1_000_000_007}return ans
}
同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/143452715
相关文章:
LeetCode 3165.不包含相邻元素的子序列的最大和:单点修改的线段树(动态规划)
【LetMeFly】3165.不包含相邻元素的子序列的最大和:单点修改的线段树(动态规划) 力扣题目链接:https://leetcode.cn/problems/maximum-sum-of-subsequence-with-non-adjacent-elements/ 给你一个整数数组 nums 和一个二维数组 q…...
ios 快捷指令扩展(Intents Extension)简单使用 swift语言
本文介绍使用Xcode15 建立快捷指令的Extension,并描述如何修改快捷指令的IntentHandler,带参数跳转主应用;以及展示多个选项的快捷指令弹框(配置intentdefinition文件),点击选项带参数跳到主应用的方法 创建快捷指令 快捷指令是…...
虚拟化环境中的精简版 Android 操作系统 Microdroid
随着移动设备的普及和应用场景的多样化,安全性和隐私保护成为了移动操作系统的重要课题。Google推出的Microdroid,是一个专为虚拟化环境设计的精简版Android操作系统,旨在提供一个安全、隔离的执行环境。本文将详细介绍Microdroid的架构、功能…...
NFTScan Site:以蓝标认证与高级项目管理功能赋能 NFT 项目
自 NFTScan Site 上线以来,它迅速成为 NFT 市场中的一支重要力量,凭借对各类 NFT 集合、市场以及 NFTfi 项目的认证获得了广泛认可。这个平台帮助许多项目提升了曝光度和可见性,为它们在竞争激烈的 NFT 市场中创造了更大的成功机会。 在最新更…...
Vue:模板 MVVM
Vue:模板 & MVVM 模板插值语法指令语法 MVVMdefineProperty数据代理 模板 Vue实例绑定一个容器,想要向容器中填入动态的值,就需要使用模板语法。模板语法分为插值语法和指令语法。 插值语法 插值语法很简单,使用{{}}包含一…...
Kafka 消息丢失如何处理?
今天给大家分享一个在面试中经常遇到的问题:Kafka 消息丢失该如何处理? 这个问题啊,看似简单,其实里面藏着很多“套路”。 来,咱们先讲一个面试的“真实”案例。 面试官问:“Kafka 消息丢失如何处理&#x…...
Mysql报错注入之floor报错详解
updatexml extractvalue floor 是mysql的函数 groupbyrandfloorcount 一、简述 利用 select count(),(floor(rand(0)2))x from table group by x,导致数据库报错,通过 concat 函数,连接注入语句与 floor(rand(0)*2)函数,实现将…...
EPS原理笔记
EPS UE(user equipment),移动用户设备 LTE(Long Term Evolution),无线接入网部分,E-UTRAN EPC(system Architecture Evolution、Evoloed Packet Core),核心网部分,主要包括MME、S-GW、P-GW、HSS,连接Intern…...
LeetCode 876. 链表的中间结点
题目描述: 给你单链表的头结点 head ,请你找出并返回链表的中间结点。 如果有两个中间结点,则返回第二个中间结点。 示例 1: 输入:head [1,2,3,4,5] 输出:[3,4,5] 解释:链表只有一个中间结点࿰…...
划界与分类的艺术:支持向量机(SVM)的深度解析
划界与分类的艺术:支持向量机(SVM)的深度解析 1. 引言 支持向量机(Support Vector Machine, SVM)是机器学习中的经典算法,以其强大的分类和回归能力在众多领域得到了广泛应用。SVM通过找到最优超平面来分…...
题目:100条经典C语言笔试题目(1-5)
题目: 1、请填写 bool , float, 指针变量 与“零值”比较的if 语句。 提示:这里“零值”可以是 0, 0.0 , FALSE 或者“空指针” 。例如 int 变量 n 与“零值”比较的 if 语句为: (1)请写出bool flag 与“零值”比较…...
python代码编写规范及注意事项
目录 1. 注意1.1 变量与常量解释:建议的修复: 1.2 Too many arguments 和 Too many local variables解决方案1. 减少参数数量2. 减少局部变量数量3. 调整 Pylint 配置 总结 1. 注意 1.1 变量与常量 解读下面的pylint问题 C0103: Constant name “file_p…...
【Linux】命令行参数 | 环境变量
🪐🪐🪐欢迎来到程序员餐厅💫💫💫 主厨:邪王真眼 主厨的主页:Chef‘s blog 所属专栏:青果大战linux 总有光环在陨落,总有新星在闪烁 前几天在搞硬件&…...
python 使用进程池并发执行 SQL 语句
这段代码使用了 Python 的 multiprocessing 模块来实现真正的并行处理,绕过 Python 的全局解释器锁(GIL)限制,从而在多核 CPU 上并发执行多个 SQL 语句。 from pyhive import hive import multiprocessing# 建立连接 conn hive.…...
我也谈AI
“随着人工智能技术的不断发展,我们已经看到了它在各行业带来的巨大变革。在医疗行业中,人工智能技术正在被应用于病例诊断、药物研发等方面,为医学研究和临床治疗提供了新的思路和方法;在企业中,人工智能技术可以通过…...
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
大佬们好呀,这一次讲解的是二叉树的深度搜索,大佬们请阅 1.前言 ⼆叉树中的深搜(介绍) 深度优先遍历(DFS,全称为DepthFirstTraversal),是我们树或者图这样的数据结构中常⽤的⼀种…...
编写第一个 Appium 测试脚本:从安装到运行!
前言 最近接到一个测试项目,简单描述一下,需求就是:一端发送指令,另一端接受指令并处理指令。大概看了看有上百条指令,点点点岂不是废了,而且后期迭代,每次都需要点点点,想想就头大…...
mysql查表相关练习
作业要求: 单表练习: 1 . 查询出部门编号为 D2019060011 的所有员工 2 . 所有财务总监的姓名、编号和部门编号。 3 . 找出奖金高于工资的员工。 4 . 找出奖金高于工资 40% 的员工。 5 找出部门编号为 D2019090011 中所有财务总监,和…...
airtest+poco多脚本、多设备批处理运行测试用例自动生成测试报告
一:主要内容 框架功能、框架架构及测试报告效果 airtest安装、环境搭建 框架搭建、框架运行说明 框架源码 二:框架功能及测试报告效果 1. 框架功能: 该框架笔者用来作为公司的项目的前端自动化,支持pc和app,本文…...
Prometheus套装部署到K8S+Dashboard部署详解
1、添加helm源并更新 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update2、创建namespace kubectl create namespace monitoring 3、安装Prometheus监控套装 helm install prometheus prometheus-community/prome…...
App无辜躺枪?手把手教你搞定腾讯手机管家误报导致的应用商店下架
当合规应用遭遇误报下架:开发者系统性应对指南运动健康类应用被标记为金融诈骗软件?社交工具因"病毒风险"被各大商店紧急下架?这类看似荒谬的误报事件,正在成为中小开发团队的"无妄之灾"。某知名运动App开发团…...
深度学习从心电信号中解码呼吸频率:原理、实现与临床价值
1. 项目概述:从心电信号中“听”到呼吸声呼吸频率,这个我们每分钟都在进行却很少被精确量化的生命体征,在临床医学中扮演着至关重要的角色。它不仅是评估呼吸系统功能的直接指标,更是反映全身代谢、循环乃至神经系统状态的“窗口”…...
百考通智能任务书:贴合你的选题,拒绝空话假大空
毕业设计任务书是高校教学管理中的关键环节,它不仅标志着研究工作的正式启动,更是后续开题、实施、论文撰写和答辩全过程的行动依据。然而,许多学生在撰写时常常因不熟悉本专业写作规范、技术表达能力有限,或缺乏权威模板参考而陷…...
CANoe诊断测试没CDD文件怎么办?手把手教你用Fault Memory窗口和CAPL脚本读取解析DTC故障码
CANoe诊断测试无CDD文件的实战解决方案:从Fault Memory到CAPL脚本全解析当CDD文件缺失或定义不清晰时,诊断测试工程师常常陷入困境。本文将深入探讨如何利用Fault Memory窗口的基础功能,并通过CAPL脚本实现更灵活、更强大的故障码读取与解析方…...
Python UiAutomation实战:从网页数据抓取到桌面应用,一个库打通数据采集全链路
Python UiAutomation实战:打通数据采集全链路的智能解决方案 在数据驱动的商业环境中,企业常常面临跨平台数据采集的挑战——财务系统里的交易记录需要与网站后台的报表进行交叉分析,销售数据要从桌面软件导出后上传到云端处理系统。传统的人…...
styled-theming 性能优化:如何避免主题切换时的性能瓶颈
styled-theming 性能优化:如何避免主题切换时的性能瓶颈 【免费下载链接】styled-theming Create themes for your app using styled-components 项目地址: https://gitcode.com/gh_mirrors/st/styled-theming styled-theming 是一个专为 styled-components …...
微信红包助手终极指南:无需ROOT的智能抢红包解决方案
微信红包助手终极指南:无需ROOT的智能抢红包解决方案 【免费下载链接】WeChatLuckyMoney :money_with_wings: WeChats lucky money helper (微信抢红包插件) by Zhongyi Tong. An Android app that helps you snatch red packets in WeChat groups. 项目地址: ht…...
Java网络编程基础分享
在学习 Java 的过程中,网络编程是非常重要的一环。无论是后端开发、分布式系统、即时通讯、文件传输,还是游戏服务、物联网设备,都离不开网络通信一、计算机网络基础1.1 什么是计算机网络把不同地理位置、具有独立功能的计算机,通…...
Claude Code + LM Studio + CC-Switch 本地自动化编程部署指南
Claude Code LM Studio CC-Switch 本地自动化编程部署指南 本指南汇总了在 Windows 本地环境下,使用 Claude Code 配合 LM Studio 本地模型、CC-Switch 代理进行自动化编程开发的完整配置方案。 目录 硬件与模型选型LM Studio 本地模型部署CC-Switch 代理配置Cla…...
MaxEnt建模总失败?别急着换数据,先检查ArcGIS裁剪栅格这1个像素的坑
MaxEnt建模失败?ArcGIS栅格裁剪的1像素陷阱与精准修复指南当你花费数小时整理好WorldClim气候数据、本地DEM高程和物种分布数据,满心期待地点击MaxEnt的运行按钮时,屏幕上突然跳出"Error projecting, two layers have different geograp…...
