【一百零九】【算法分析与设计】树状数组求解前缀最大值,673. 最长递增子序列的个数,树状数组求前缀区间最大值

树状数组求解前缀最大值

树状数组可以求解和前缀区间有关的问题,例如前缀和,前缀区间最值.
可以利用 l o g n log_n logn的时间复杂度快速查找前缀信息.
利用树状数组查询前缀区间中最大值问题.
在这里插入图片描述
树状数组下标1位置存储arr数组下标1位置的最大值.
树状数组2位置存储arr数组1,2位置最大值.
数组数组3位置存储arr数组3位置最大值.
以此类推…
查找arr数组1~i前缀区间最大值.利用lowbit跳转,记录遍历的每一个tree[i]的最大值.

lowbit跳转,while(i<tree.size()),i+=lowbit(i),i会遍历所有拥有i位置的数组数组位置.
while(i>0)i-=lowbit(i),i会遍历所有能够组成1,2,3…i的树状数组位置.
在这里插入图片描述
如果i位置是7,lowbit往前跳转,树状数组会遍历4,6,7位置,对应arr组成1,2,3,4,5,6,7.
往后跳转,树状数组会遍历7,8,拥有arr中7位置的树状数组位置.

#include<bits/stdc++.h>
using namespace std;

#define int long long // 定义 int 为 long long 类型,方便处理大数
#define endl '\n' // 定义 endl 为换行符,方便输出

vector<int> arr = { 1, 4, 2, 5, 3, 5, 6, 3, 2, 5 }; // 定义一个全局数组并初始化

// 树状数组类定义
class Tree {
public:
    vector<int> tree; // 定义一个向量 tree,用于存储树状数组

    // 计算 lowbit
    int lowbit(int i) {
        return i & -i; // 返回 i 和 -i 的按位与,获取最低位的 1
    }

    // 在位置 i 处更新值 v
    void sett(int i, int v) {
        while (i <= tree.size()) { // 从索引 i 开始,向上更新树状数组
            tree[i] = max(tree[i], v); // 更新节点为当前值和新值的最大值
            i += lowbit(i); // 移动到下一个需要更新的位置
        }
    }

    // 查询前缀 [1, i] 的最大值
    int gett(int i) {
        int ret = LLONG_MIN; // 初始化结果为负无穷大
        while (i > 0) { // 从索引 i 开始,向下计算前缀最大值
            ret = max(tree[i], ret); // 更新结果为当前值和当前结果的最大值
            i -= lowbit(i); // 移动到下一个需要计算的位置
        }
        return ret; // 返回前缀最大值
    }

    // 默认构造函数
    Tree() {}

    // 使用给定大小 n 初始化树状数组
    Tree(int n) {
        tree.assign(n + 3, 0); // 初始化树状数组大小,并将值设为 0
    }

    // 使用给定数组初始化树状数组
    Tree(vector<int> arr) {
        tree.assign(arr.size() + 3, LLONG_MIN); // 初始化树状数组大小,并将值设为负无穷大
        int i = 1;
        for (auto& xx : arr) {
            sett(i++, xx); // 将数组中的值添加到树状数组中
        }
    }
};

Tree t1(arr); // 使用全局数组初始化树状数组 t1
int q; // 定义查询次数

// 主解题函数
void solve() {
    for (auto& xx : arr) {
        cout << xx << " "; // 输出数组中的每个元素
    }
    cout << endl;
    for (int i = 0; i < arr.size(); i++) {
        cout << i << " "; // 输出数组的索引
    }
    cout << endl;
    cin >> q; // 读取查询次数
    for (int i = 1; i <= q; i++) {
        int k;
        cin >> k; // 读取查询索引
        k++;
        cout << t1.gett(k) << endl; // 输出前缀 [1, k] 的最大值
    }
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); // 快速输入输出

    solve(); // 调用解题函数
}

673. 最长递增子序列的个数

给定一个未排序的整数数组 nums , 返回最长递增子序列的个数 。

注意 这个数列必须是 严格 递增的。

示例 1:

输入: [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。
示例 2:

输入: [2,2,2,2,2]
输出: 5
解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。

提示:

1 < = n u m s . l e n g t h < = 2000 1 <= nums.length <= 2000 1<=nums.length<=2000
− 1 0 6 < = n u m s [ i ] < = 1 0 6 -10^6 <= nums[i] <= 10^6 106<=nums[i]<=106

countt数组,对应arr数组每一个元素.
countt存储node类型,node类型有两个变量,maxlen和count.
countt[i].maxlen表示arr数组中以i位置元素为结尾的最长递增子序列的长度,countt[i].count表示arr数组中以i位置元素为结尾的最长递增子序列的个数.
如果countt数组维护完,只需要直到最长递增子序列的长度,然后遍历countt数组,统计是最长递增子序列长度的个数即可.

填写countt[i]位置的数据,需要直到1~i-1区间中,元素值小于arr[i]的最长递增子序列的长度,以及个数.
元素值小于arr[i],对应词频表,元素值映射个数,词频.元素值作为下标,刚好是排序好的,也就是求前缀和.
1~i-1,对应依次遍历.
利用树状数组存储以某元素值为结尾的最长递增子序列的长度,元素值映射最长的长度.
在这里插入图片描述
index映射arr,元素值映射index,index映射maxlen.

利用map做离散化处理.
利用树状数组查询1~i-1以小于arr[i]元素结尾的最长递增子序列的长度.
然后遍历arr数组,统计数量.维护当前位置countt.

Tree中gett函数获取1~i最大值,但是如果进来的i是0,直接返回0,最大长度不存在.因为外面要用这个最大长度+1表示当前的最大长度.

struct node {
    int maxlen = 1, count = 0; // 定义节点结构,包含最大长度和计数
};

class Tree {
public:
    vector<int> tree; // 定义一个向量 tree,用于存储树状数组

    // 计算 lowbit
    int lowbit(int i) { 
        return i & -i; // 返回 i 和 -i 的按位与,获取最低位的 1
    }

    // 在位置 i 处更新值 v
    void sett(int i, int v) {
        while (i < tree.size()) { // 从索引 i 开始,向上更新树状数组
            tree[i] = max(tree[i], v); // 更新节点为当前值和新值的最大值
            i += lowbit(i); // 移动到下一个需要更新的位置
        }
    }

    // 查询前缀 [1, i] 的最大值
    int gett(int i) {
        int ret = INT_MIN; // 初始化结果为负无穷大
        if (i == 0) // 如果索引为 0
            return 0; // 返回 0
        while (i > 0) { // 从索引 i 开始,向下计算前缀最大值
            ret = max(ret, tree[i]); // 更新结果为当前值和当前结果的最大值
            i -= lowbit(i); // 移动到下一个需要计算的位置
        }
        return ret; // 返回前缀最大值
    }

    // 默认构造函数
    Tree() {}
};

class Solution {
public:
    Tree t1; // 定义一个树状数组对象 t1
    vector<int> arr; // 定义一个向量 arr,用于存储输入的数组
    map<int, int> arr_index; // 定义一个 map,用于存储数组元素的索引
    vector<node> countt; // 定义一个向量 countt,用于存储每个位置的节点信息
    int ret = 0; // 定义一个变量 ret,用于存储结果
    int maxnlen = 0; // 定义一个变量 maxnlen,用于存储最大长度

    // 主解题函数
    void solve() {
        maxnlen = 0; // 初始化最大长度为 0
        ret = 0; // 初始化结果为 0
        arr_index.clear(); // 清空索引 map
        for (auto& x : arr) { // 遍历输入数组
            arr_index[x]; // 在 map 中记录每个元素
        }
        int index = 1;
        for (auto& x : arr_index) { // 给每个元素分配唯一的索引
            x.second = index++;
        }
        countt.assign(arr.size(), node()); // 初始化 countt 向量
        t1.tree.assign(index, 0); // 初始化树状数组
        for (int i = 0; i < arr.size(); i++) { // 遍历数组
            int index = arr_index[arr[i]]; // 获取当前元素的索引
            int maxlen = t1.gett(index - 1); // 获取当前索引之前的最大长度
            int ans = 0;
            for (int j = 0; j < i; j++) { // 遍历之前的元素
                if (countt[j].maxlen == maxlen && arr[j] < arr[i]) { // 找到符合条件的元素
                    ans += countt[j].count; // 累加计数
                }
            }
            countt[i].maxlen = maxlen + 1; // 更新当前元素的最大长度
            countt[i].count = max(ans, 1); // 更新当前元素的计数
            t1.sett(index, countt[i].maxlen); // 在树状数组中更新当前元素的最大长度
            maxnlen = max(maxnlen, countt[i].maxlen); // 更新最大长度
        }

        for (int i = 0; i < countt.size(); i++) { // 遍历 countt 向量
            if (countt[i].maxlen == maxnlen) { // 找到最大长度的元素
                ret += countt[i].count; // 累加结果
            }
        }
    }

    // 查找最长递增子序列的数量
    int findNumberOfLIS(vector<int>& _nums) {
        ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); // 快速输入输出
        arr = _nums; // 将输入数组赋值给 arr
        solve(); // 调用解题函数
        return ret; // 返回结果
    }
};


结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。
同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。
谢谢您的支持,期待与您在下一篇文章中再次相遇!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024 cicsn SuperHeap

文章目录 参考沙箱存在protobuf逆向buy_booksee_bookreturn_bookedit_booksearch_book 思路exp 参考 https://hakuya.work/post/7 https://akaieurus.github.io/2024/05/20/2024%E5%9B%BD%E8%B5%9B%E5%88%9D%E8%B5%9Bpwn-wp/#SuperHeap https://blog.csdn.net/m0_63437215/art…

html--圣诞树

将以下代码保存到txt文件中&#xff0c;并改名为xx.html <html> <head> <title>圣诞树</title> <meta charset"utf-8" > <style> html, body { width: 100%; height: 100%; margin: 0; padding: 0; border: 0; } div { margin: …

Windows 找不到文件‘shell:sendto‘。请确定文件名是否正确后,再试一次

执行“shell:sendto”命令的时候&#xff0c;报错&#xff1a;Windows 找不到文件’shell:sendto’。请确定文件名是否正确后&#xff0c;再试一次 解决办法&#xff1a; 在桌面新建一个记事本文件命名为fix.reg&#xff0c;注意后缀是reg&#xff0c;文件中填写以下内容&…

常见机器学习概念

信息熵 信息熵&#xff08;information entropy&#xff09;是信息论的基本概念。描述信息源各可能事件发生的不确定性。20世纪40年代&#xff0c;香农&#xff08;C.E.Shannon&#xff09;借鉴了热力学的概念&#xff0c;把信息中排除了冗余后的平均信息量称为“信息熵”&…

课时149:项目发布_基础知识_项目交付

1.1.1 项目交付 学习目标 这一节&#xff0c;我们从 基础知识、代码发布、小结 三个方面来学习 基础知识 简介 项目交付是一个涉及到多团队共同协作的事情&#xff0c;它包括 产品团队设计产品、研发团队开发产品、测试团队测试代码、运维团队发布代码和维护站点等工作。项…

Bev 车道标注方案及复杂车道线解决

文章目录 1. 数据采集方案1.1 传感器方案1.2 数据同步2. 标注方案2.1 标注注意项2.2 4d 标注(时序)2.2.1 4d标签制作2.2.2 时序融合的作用2.2.2.1 时序融合方式2.2.2.2 时序融合难点2.2.2.2 时序实际应用情况3. 复杂车道线解决3.1 split 和merge车道线的解决3.2 大曲率或U形车道…

56.WEB渗透测试-信息收集- 端口、目录扫描、源码泄露(4)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;55.WEB渗透测试-信息收集- 端口、目录扫描、源码泄露&#xff08;3&#xff09; 如果把文…

数据挖掘--数据仓库与联机分析处理

什么是数据仓库 &#xff08;面集时非&#xff09; 面向主题的&#xff1a;围绕某一主题来构建集成的&#xff1a;图片文字杂糅在一起时变的&#xff1a;随时间变化的数据非易失的&#xff1a;硬盘存放&#xff0c;不易丢失 操作数据库系统&#xff08;OLTP)与数据仓库(OLAP…

原力、百度、人人文档下载工具

只可下载可预览的文档&#xff0c;格式为pdf&#xff0c;不能完全保证下载成功&#xff0c;X度与我们既是对手也是朋友。 本文的软件来自的大神&#xff0c;仅供学习交流&#xff0c;不可做它用。 向的大神致敬&#xff01;&#xff01;&#xff01;

C语言 | Leetcode C语言题解之第137题只出现一次的数字II

题目&#xff1a; 题解&#xff1a; int singleNumber(int *nums, int numsSize) {int a 0, b 0;for (int i 0; i < numsSize; i) {b ~a & (b ^ nums[i]);a ~b & (a ^ nums[i]);}return b; }

【CS.CN】深入解析HTTP中的Expect: 100-continue头:性能优化的利器还是鸡肋?

目录 0 序言 0.1 由来0.2 使用场景0.3 现在还需要吗&#xff1f; 1 Expect: 100-continue的机制2 语法 && 通过重新设置空的Expect头优化性能3 实例分析&#xff1a;长连接中的Expect问题解决4 总结 0 序言 0.1 由来 Expect: 100-continue头部字段最早在HTTP/1.1规…

Matplotlib常见图汇总

Matplotlib是python的一个画图库&#xff0c;便于数据可视化。 安装命令 pip install matplotlib 常用命令&#xff1a; 绘制直线&#xff0c;连接两个点 import matplotlib.pyplot as plt plt.plot([0,5],[2,4]) plt.show() 运行结果如下&#xff1a; 多条线&#xff1a;…

calibre,一个超厉害的 Python 库!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超厉害的 Python 库 - calibre。 Github地址&#xff1a;https://github.com/kovidgoyal/calibre 电子书籍已经成为现代阅读的重要形式&#xff0c;而管理和转换电子书籍格式的需求也随之增加…

Linux系统信息的查看

目录 前言一、系统环境二、查看系统IP地址信息2.1 ifconfig命令2.2 ip address命令 三、查看系统端口信息3.1 nmap命令3.2 netstat命令 四、查看系统进程信息4.1 ps命令4.2 kill命令 五、查看系统监控信息5.1 top命令5.2 df命令iostat命令5.3 sar命令 总结 前言 本篇文章介绍查…

控制台输入javac命令输出的结果中的中文乱码解决方式

默认字符编码UTF-8无法解析中文。设置环境变量中 “JAVA_TOOL_OPTIONS” 的值为"UTF-8" 即可。 具体配置步骤&#xff1a; 桌面右键"我的电脑" --> 属性 高级系统设置 环境变量 用户变量中添加 JAVA_TOOL_OPTIONS 然后确定&#xff0c;保存即可。

Locust:用Python编写可扩展的负载测试

Locust&#xff1a;简化性能测试&#xff0c;让负载模拟更直观- 精选真开源&#xff0c;释放新价值。 概览 Locust是一个开源的性能和负载测试工具&#xff0c;专门用于HTTP和其他协议的测试。它采用开发者友好的方法&#xff0c;允许用户使用普通的Python代码来定义测试场景。…

docker 命令 ps,inspect,top,logs详解

docker常用命令教程-4 docker ps docker ps 命令用于列出当前正在运行的容器。默认情况下&#xff0c;它只显示正在运行的容器&#xff0c;但你可以使用 -a 或 --all 选项来显示所有容器&#xff08;包括已停止的容器&#xff09;。 常用的选项和示例&#xff1a; -a 或 --…

CW32F030K8T7单片机在即热式热水器的应用介绍

随着智能家居技术的不断进步&#xff0c;即热式热水器作为现代家庭中的重要组成部分&#xff0c;正逐渐向智能化、节能化方向发展。本方案通过采用武汉芯源半导体的CW32F030系列单片机&#xff0c;以其高性能、超强抗干扰等特性&#xff0c;为即热式热水器的智能化提供了理想的…

(UE4.26)UE4的FArchive序列化入门

前言 序列化(Serialize)和反序列化(UnSerialize)是程序领域常见的概念。对于这两个词汇我理解的是 序列化(Serialize): 变量值(int, float, string等基本类型, 或者Array&#xff0c;Map&#xff0c;或者更复杂的复合体)存储为一个文件(二进制流, 二进制文件, json, xml等格式…

CorelDRAW2024最新crack+keygen安装包下载

在数字艺术的浪潮下&#xff0c;设计师对于设计工具的需求也愈发严苛&#xff0c;他们希望有一款能够提供强大功能和灵活操作的软件来帮助他们实现更专业、更具创新力的设计。近日发布的CorelDRAW 2024正是这样一款能够满足设计师需求的专业图形设计软件。 「CorelDRAW汉化版下…