当前位置: 首页 > news >正文

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] <= 105
  • 1 <= queries.length <= 5 * 104
  • queries[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.不包含相邻元素的子序列的最大和&#xff1a;单点修改的线段树&#xff08;动态规划&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/maximum-sum-of-subsequence-with-non-adjacent-elements/ 给你一个整数数组 nums 和一个二维数组 q…...

ios 快捷指令扩展(Intents Extension)简单使用 swift语言

本文介绍使用Xcode15 建立快捷指令的Extension&#xff0c;并描述如何修改快捷指令的IntentHandler&#xff0c;带参数跳转主应用&#xff1b;以及展示多个选项的快捷指令弹框(配置intentdefinition文件)&#xff0c;点击选项带参数跳到主应用的方法 创建快捷指令 快捷指令是…...

虚拟化环境中的精简版 Android 操作系统 Microdroid

随着移动设备的普及和应用场景的多样化&#xff0c;安全性和隐私保护成为了移动操作系统的重要课题。Google推出的Microdroid&#xff0c;是一个专为虚拟化环境设计的精简版Android操作系统&#xff0c;旨在提供一个安全、隔离的执行环境。本文将详细介绍Microdroid的架构、功能…...

NFTScan Site:以蓝标认证与高级项目管理功能赋能 NFT 项目

自 NFTScan Site 上线以来&#xff0c;它迅速成为 NFT 市场中的一支重要力量&#xff0c;凭借对各类 NFT 集合、市场以及 NFTfi 项目的认证获得了广泛认可。这个平台帮助许多项目提升了曝光度和可见性&#xff0c;为它们在竞争激烈的 NFT 市场中创造了更大的成功机会。 在最新更…...

Vue:模板 MVVM

Vue&#xff1a;模板 & MVVM 模板插值语法指令语法 MVVMdefineProperty数据代理 模板 Vue实例绑定一个容器&#xff0c;想要向容器中填入动态的值&#xff0c;就需要使用模板语法。模板语法分为插值语法和指令语法。 插值语法 插值语法很简单&#xff0c;使用{{}}包含一…...

Kafka 消息丢失如何处理?

今天给大家分享一个在面试中经常遇到的问题&#xff1a;Kafka 消息丢失该如何处理&#xff1f; 这个问题啊&#xff0c;看似简单&#xff0c;其实里面藏着很多“套路”。 来&#xff0c;咱们先讲一个面试的“真实”案例。 面试官问&#xff1a;“Kafka 消息丢失如何处理&#x…...

Mysql报错注入之floor报错详解

updatexml extractvalue floor 是mysql的函数 groupbyrandfloorcount 一、简述 利用 select count(),(floor(rand(0)2))x from table group by x&#xff0c;导致数据库报错&#xff0c;通过 concat 函数&#xff0c;连接注入语句与 floor(rand(0)*2)函数&#xff0c;实现将…...

EPS原理笔记

EPS UE(user equipment)&#xff0c;移动用户设备 LTE(Long Term Evolution)&#xff0c;无线接入网部分&#xff0c;E-UTRAN EPC(system Architecture Evolution、Evoloed Packet Core)&#xff0c;核心网部分&#xff0c;主要包括MME、S-GW、P-GW、HSS&#xff0c;连接Intern…...

LeetCode 876. 链表的中间结点

题目描述: 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释&#xff1a;链表只有一个中间结点&#xff0…...

划界与分类的艺术:支持向量机(SVM)的深度解析

划界与分类的艺术&#xff1a;支持向量机&#xff08;SVM&#xff09;的深度解析 1. 引言 支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是机器学习中的经典算法&#xff0c;以其强大的分类和回归能力在众多领域得到了广泛应用。SVM通过找到最优超平面来分…...

题目:100条经典C语言笔试题目(1-5)

题目&#xff1a; 1、请填写 bool , float, 指针变量 与“零值”比较的if 语句。 提示&#xff1a;这里“零值”可以是 0, 0.0 , FALSE 或者“空指针” 。例如 int 变量 n 与“零值”比较的 if 语句为&#xff1a; &#xff08;1&#xff09;请写出bool flag 与“零值”比较…...

python代码编写规范及注意事项

目录 1. 注意1.1 变量与常量解释&#xff1a;建议的修复&#xff1a; 1.2 Too many arguments 和 Too many local variables解决方案1. 减少参数数量2. 减少局部变量数量3. 调整 Pylint 配置 总结 1. 注意 1.1 变量与常量 解读下面的pylint问题 C0103: Constant name “file_p…...

【Linux】命令行参数 | 环境变量

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;青果大战linux 总有光环在陨落&#xff0c;总有新星在闪烁 前几天在搞硬件&…...

python 使用进程池并发执行 SQL 语句

这段代码使用了 Python 的 multiprocessing 模块来实现真正的并行处理&#xff0c;绕过 Python 的全局解释器锁&#xff08;GIL&#xff09;限制&#xff0c;从而在多核 CPU 上并发执行多个 SQL 语句。 from pyhive import hive import multiprocessing# 建立连接 conn hive.…...

我也谈AI

“随着人工智能技术的不断发展&#xff0c;我们已经看到了它在各行业带来的巨大变革。在医疗行业中&#xff0c;人工智能技术正在被应用于病例诊断、药物研发等方面&#xff0c;为医学研究和临床治疗提供了新的思路和方法&#xff1b;在企业中&#xff0c;人工智能技术可以通过…...

算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝

大佬们好呀&#xff0c;这一次讲解的是二叉树的深度搜索&#xff0c;大佬们请阅 1.前言 ⼆叉树中的深搜&#xff08;介绍&#xff09; 深度优先遍历&#xff08;DFS&#xff0c;全称为DepthFirstTraversal&#xff09;&#xff0c;是我们树或者图这样的数据结构中常⽤的⼀种…...

编写第一个 Appium 测试脚本:从安装到运行!

前言 最近接到一个测试项目&#xff0c;简单描述一下&#xff0c;需求就是&#xff1a;一端发送指令&#xff0c;另一端接受指令并处理指令。大概看了看有上百条指令&#xff0c;点点点岂不是废了&#xff0c;而且后期迭代&#xff0c;每次都需要点点点&#xff0c;想想就头大…...

mysql查表相关练习

作业要求&#xff1a; 单表练习&#xff1a; 1 . 查询出部门编号为 D2019060011 的所有员工 2 . 所有财务总监的姓名、编号和部门编号。 3 . 找出奖金高于工资的员工。 4 . 找出奖金高于工资 40% 的员工。 5 找出部门编号为 D2019090011 中所有财务总监&#xff0c;和…...

airtest+poco多脚本、多设备批处理运行测试用例自动生成测试报告

一&#xff1a;主要内容 框架功能、框架架构及测试报告效果 airtest安装、环境搭建 框架搭建、框架运行说明 框架源码 二&#xff1a;框架功能及测试报告效果 1. 框架功能&#xff1a; 该框架笔者用来作为公司的项目的前端自动化&#xff0c;支持pc和app&#xff0c;本文…...

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…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...