Studying-刷题补充| 数组:58.区间和、44. 开发商购买土地

news2024/9/21 14:40:53

目录

58.区间和

44. 开发商购买土地 

总结 


58.区间和

文档讲解:代码随想录58.区间和

题目:58. 区间和(第九期模拟笔试) (kamacoder.com)

学习:本题最直接的做法是,将数组Array保存好后,通过下标遍历数组,以此来计算区间的总和。代码也很直观:保存数组,计算总和即可

#include <iostream>
#include <vector>
using namespace std;
int main() {
    int n, a, b;
    cin >> n;
    vector<int> vec(n);
    for (int i = 0; i < n; i++) cin >> vec[i];
    while (cin >> a >> b) {
        int sum = 0;
        // 累加区间 a 到 b 的和
        for (int i = a; i <= b; i++) sum += vec[i];
        cout << sum << endl;
    }
} 

但是这种方法,在本题中会存在超时的情况,因为这种解法,每次我们都需要遍历数组上下标,来计算区间的总和。假如存在一个极端的情况,我们查询m次,每次查询的范围都是0到n - 1,则该算法的时间复杂度为O(m * n)其中m为查询的次数,可见时间复杂度是很高的。

因此我们可以采取另一种方法来解决本题:前缀和。

前缀和在涉及计算区间和的问题时非常有用。前缀和的思想是重复利用计算过的子数组之和,从而降低区间查询需要累加计算的次数。

其实很好理解,我们通过保存每个下标i(包括i)之前元素的累加和,就能够很容易得得到,某个区间的总和,例如:

此时如果我们想要统计数组下标1,3之间的累加和,我们只需要使用p[3] - p[0]即可。这是因为p[3]包含了下标3之前元素的和,而p[0]包含了下标0之前元素的和。这样一减,剩下的就是下标1到下标3之间的元素的和了。 

又比如下标2和下标5之间,就是p[5] - p[1]:

p[1] = vec[0] + vec[1];

p[5] = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5];

p[5] - p[1] = vec[2] + vec[3] + vec[4] + vec[5]; 

这样的话,我们再处理好前缀和数组后,每一次查找两个下标之间的区间和,时间复杂度就为O(1),极大的降低了时间复杂度。

这里要注意两点:

  1. 我们在进行前缀和减的时候是p[b] - p[a - 1]而不是p[a],这是因为我们需要下标a的值,区间是左闭右闭的。
  2. 又因为上述的原因,当a = 0时,我们需要单独处理情况,不需要减了,p[b]就是我们需要的值。 
#include <iostream>
#include <vector>
using namespace std;
 
 
int main() {
    int n, a, b;
    cin >> n;
    vector<int> Arraysum(n); //记录前缀和
    int ans;
    int sum = 0;
    for(int i = 0; i < n; i++) {
        cin >> ans;
        sum += ans;
        Arraysum[i] = sum;
    }
     
    while(cin >> a >> b) {
        int presum;
        if(a == 0) {
            presum = Arraysum[b];
        }
        else {
            presum = Arraysum[b] - Arraysum[a - 1];
        }
        cout << presum << endl;
    }
    return 0;
}

C++代码,面对大量数据读取输出操作的时候,可以使用scanf 和 printf,耗时会减少很多:

#include <iostream>
#include <vector>
using namespace std;
int main() {
    int n, a, b;
    cin >> n;
    vector<int> vec(n);
    vector<int> p(n);
    int presum = 0;
    for (int i = 0; i < n; i++) {
        scanf("%d", &vec[i]);
        presum += vec[i];
        p[i] = presum;
    }

    while (~scanf("%d%d", &a, &b)) {
        int sum;
        if (a == 0) sum = p[b];
        else sum = p[b] - p[a - 1];
        printf("%d\n", sum);
    }
}

44. 开发商购买土地 

文档讲解:代码随想录44.开发商购买土地

题目: 44. 开发商购买土地(第五期模拟笔试) (kamacoder.com)

学习:本题是一个分割问题,关键是只能纵向或者横向切割,并且根据题意只能切割一刀。本题存在暴力的解法,时间复杂度是O(n^3),使用一个for枚举分割线,嵌套两个for去累加区间里的和进行求解。

但我们可以根据上题的前缀和的思想,来进行时间复杂度的优化。

首先根据本题,我们只能纵向或者横向的切一刀,这就是两种情况,分别对应行分割和列分割。

1.行分割:对于行分割来说,我们可以理解为切一刀后,该位置之前的和就为A公司的区域和 sumA,而B公司的区域和为sumB = sum - sumA,而B公司和A公司的差值就为两者相减:

abs(sum - sumA - sumA)

可见其实我们只需要遍历A公司的区域和就可。因此我们先预处理数组,将其每一行的和求出来,再遍历行和数组,来确定A公司的区域和,以此来找到两个公司最小的差值。

result = min(result, abs(sum - sumA - sumA))

2.列分割:列分割同理,我们同样预处理数组,计算每一列的和,然后再遍历列和数组,来计算最小差值。

最终可以得到代码:时间复杂度为O(n^2)

#include <iostream>
#include <vector>
#include <climits>

using namespace std;
int main () {
    int n, m;
    cin >> n >> m;
    int sum = 0;
    vector<vector<int>> vec(n, vector<int>(m, 0)) ;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> vec[i][j];
            sum += vec[i][j];
        }
    }
    // 统计横向
    vector<int> horizontal(n, 0);
    for (int i = 0; i < n; i++) {
        for (int j = 0 ; j < m; j++) {
            horizontal[i] += vec[i][j];
        }
    }
    // 统计纵向
    vector<int> vertical(m , 0);
    for (int j = 0; j < m; j++) {
        for (int i = 0 ; i < n; i++) {
            vertical[j] += vec[i][j];
        }
    }
    int result = INT_MAX;
    int horizontalCut = 0;
    for (int i = 0 ; i < n; i++) {
        horizontalCut += horizontal[i];
        result = min(result, abs(sum - horizontalCut - horizontalCut));
    }
    int verticalCut = 0;
    for (int j = 0; j < m; j++) {
        verticalCut += vertical[j];
        result = min(result, abs(sum - verticalCut - verticalCut));
    }
    cout << result << endl;
}

我们也可以进行一些优化: 实际上超过sum/2后,计算一次即可,后面差值只会越来越大

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int main() {

    int n, m;
    cin >> n >> m;
    
    vector<vector<int>> vec(n, vector<int>(m, 0));
    int sum = 0; //统计总和
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            cin >> vec[i][j];
            sum += vec[i][j];
        }
    }
    
    //统计行和
    vector<int> linesum(n, 0);
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            linesum[i] += vec[i][j];
        }
    }
    //统计列和
    vector<int> colusum(m, 0);
    for(int j = 0; j < m; j++) {
        for(int i = 0; i < n; i++) {
            colusum[j] += vec[i][j];
        }
    }
    
    int result = INT_MAX;
    int horisum = 0;
    for(int i = 0; i < n; i++) {
        horisum += linesum[i];
        result = min(result, abs(sum - horisum - horisum));
        if(horisum > sum/2) { //优化,实际上超过sum/2后,计算一次即可,后面差值只会越来越大
            break;
        }
    }
    
    int versum = 0;
    for(int j = 0; j < m; j++) {
        versum += colusum[j];
        result = min(result, abs(sum - versum - versum));
        if(versum > sum/2) { //优化,实际上超过sum/2后,计算一次即可,后面差值只会越来越大
            break;
        }
    }
    cout << result << endl;
    return 0;
}

本题也可以在暴力求解的基础上,优化一下,就不用前缀和了,在行向遍历的时候,遇到行末尾就统一一下, 在列向遍历的时候,遇到列末尾就统计一下。时间复杂度也是O(n^2),空间复杂度稍微降低了一些。

#include <iostream>
#include <vector>
#include <climits>

using namespace std;
int main () {
    int n, m;
    cin >> n >> m;
    int sum = 0;
    vector<vector<int>> vec(n, vector<int>(m, 0)) ;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> vec[i][j];
            sum += vec[i][j];
        }
    }

    int result = INT_MAX;
    int count = 0; // 统计遍历过的行
    for (int i = 0; i < n; i++) {
        for (int j = 0 ; j < m; j++) {
            count += vec[i][j];
            // 遍历到行末尾时候开始统计
            if (j == m - 1) result = min (result, abs(sum - count - count));

        }
    }

    count = 0; // 统计遍历过的列
    for (int j = 0; j < m; j++) {
        for (int i = 0 ; i < n; i++) {
            count += vec[i][j];
            // 遍历到列末尾的时候开始统计
            if (i == n - 1) result = min (result, abs(sum - count - count));
        }
    }
    cout << result << endl;
}

总结 

数组的一些补充题型,前缀和的使用。实际上前缀和在后续动态规划中,同样也会被使用。 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux - mathematica 安装教程

注意事项&#xff1a; 文件目录不能有空格&#xff0c;不能有中文 安装包 Mathematica - 12.1 安装 解压软件包 7z x Mathematica_12.1.1_LINUX_CN.zip运行安装器 命令运行后解压出Mathematica_12.1.1_LINUX_CN.sh, 运行该安装脚本 chmod x Mathematica_12.1.1_LINUX_CN…

STM32后备区域:读写BKP备份寄存器与使用RTC实时时钟详解

目录 STM32后备区域&#xff1a;读写BKP备份寄存器与使用RTC实时时钟详解 1 什么是STM32的后备区域 分割线* 2.1 BKP备份寄存器简介 2.2 BKP备份寄存器基本结构 2.3 BKP外设头文件 bkp.h介绍 2.4 读写 BKP备份寄存器 操作步骤 2.5 编写 读写备份寄存器 5.1 文件介绍 …

Centos7 系统下安装go语言开发环境

该文章简述在Centos7 amd64 系统中安装go开发环境的方法。 一、golang官网查看对应平台最新的golang版本 Golang 官网地址&#xff1a;All releases - The Go Programming Language 二、 安装GO的过程及相关命令 # 1、下载go&#xff0c;这里使用 go1.22.5 版本&#xff0c;可…

【ACL2024】基于长尾检索知识增强的大语言模型

近日&#xff0c;阿里云人工智能平台PAI与阿里集团安全部内容安全算法团队、华东师范大学何晓丰教授团队合作&#xff0c;在自然语言处理顶级会议ACL2024上发表论文《On the Role of Long-tail Knowledge in Retrieval Augmented Large Language Models》&#xff0c;论文主题为…

爆火游戏《黑神话:悟空》研发背后有哪些故事?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门面向中国程序员和企业提供企业级一体化 DevOps 平台&#xff0c;用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规&#xff0c;而且所有的操作都是在一个平台上进行&#xff0c;省事省心省钱。可以一键安装极狐GitL…

美团的测试面试题,真的很难吗?

年前&#xff0c;我的一个粉丝留言给我说&#xff0c;他在面试美团的自动化测试岗的时候&#xff0c;不幸挂掉了。 越想越可惜&#xff0c;回想面试经过&#xff0c;好好总结了几个点&#xff0c;发现面试没过的主要原因是在几个关键的问题没有给到面试官想要的答案 美团的面…

寻访中国100家.NET中大企业 —— 第二站:苏州行

一&#xff1a;事情起因 在.NET圈里混了十多年&#xff0c;相信有不少人知道我专注于玩 .NET高级调试&#xff0c;如今技术上的硬实力还是能够解决市面上的一些疑难杂症&#xff0c;但软实力却在另一个极端&#xff0c;如&#xff08;人际交往&#xff0c;人情事故&#xff09…

[RCTF2015]EasySQL1

打开题目 点进去看看 注册个admin账户&#xff0c;登陆进去 一个个点开看&#xff0c;没发现flag 我们也可以由此得出结论&#xff0c;页面存在二次注入的漏洞&#xff0c;并可以大胆猜测修改密码的源代码 resoponse为invalid string的关键字是被过滤的关键字&#xff0c;Le…

氟化工特氟龙精馏装置:PFA氟化氢反应装置的应用

精馏装置是进行精馏的一种塔式气液接触装置。利用混合物中各组分具有不同的挥发度&#xff0c;即在同一温度下各组分的蒸气压不同这一性质&#xff0c;使液相中的轻组分&#xff08;低沸物&#xff09;转移到气相中。 实验精馏装置的组成 实验精馏装置通常由以下几部分组成&am…

Linux2.6设备驱动开发

一&#xff1a;Linux2.6驱动设备开发的特点 1&#xff1a;首先是属于字符型设备注册的方法之一 这种开发接口是在Linux2.6引入的&#xff0c;之前的版本不支持这种开发方式&#xff0c;也是目前最标准的开发方式。 2&#xff1a;Linux2.6的设备开发 不再去限制设备号&#xf…

(javaweb)SpringBootWeb案例(毕业设计)案例--部门管理

目录 1.准备工作 2.部门管理--查询功能 3.前后端联调 3.部门管理--新增功能 1.准备工作 mapper数据访问层相当于dao层 根据页面原型和需求分析出接口文档--前后端必须遵循这种规范 大部分情况下 接口文档由后端人员来编写 前后端进行交互基于restful风格接口 http的请求方式…

TypeScript学习笔记(二)——TypeScript 高级类型

目录 1. class 类 1.1 class 关键字的基本使用 1.2 类继承 1.3 类成员可见性 1.4 类成员只读修饰符 2. 类型兼容性 2.1 类型兼容性 2.2 接口兼容性 2.3 函数兼容性 3. 交叉类型 4. 泛型 4.1 创建泛型函数 4.2 泛型约束 4.3 多个泛型的类型变量约束 4.4 泛型接口…

【深度学习入门项目】基于支持向量机的手写数字识别

目录 导入必要的包1. 数据集2. 数据处理3. 训练过程4. 输出结果完整代码 本项目使用SVM训练模型&#xff0c;用于预测手写数字图片。 导入必要的包 numpy: 这个库是Python中常用的数学计算库。在这个项目中&#xff0c;我使用numpy来处理图像数据&#xff0c;将图像数据转换为…

FPGA开发——DS18B20读取温度并且在数码管上显示

一、简介 在上一篇文章中我们对于DS18B20的相关理论进行了详细的解释&#xff0c;同时也对怎样使用DS18B20进行了一个简单的叙述。在这篇文章我们通过工程来实现DS18B20的温度读取并且实现在数码管伤显示。 1、基本实现思路 根据不同时刻的操作&#xff0c;我们可以使用一个状…

基于vue框架的班级网站的设计与实现vg66m(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;班级,学生,班级活动,班级相册,班级开支,活动记录 开题报告内容 基于Vue框架的班级网站设计与实现 开题报告 一、引言 随着互联网技术的飞速发展&#xff0c;网络已经成为人们日常生活中不可或缺的一部分。在教育领域&#xff0c;班级…

大白话解析:深入浅出大模型RAG模块全解析

文章目录 什么是 RAG&#xff1f; 技术交流&资料通俗易懂讲解大模型系列 RAG模块化 什么是模块化RAG&#xff1f; 索引模块 块优化 滑动窗口从小到大元数据附加 结构化组织 层次化索引知识图谱文档组织 预检索模块 查询扩展 多查询子查询CoVe 查询转换 重写HyDE 查询路由…

TON链上游戏项目开发基本要求及模式创建与海外宣发策略

TON&#xff08;The Open Network&#xff09;是由Telegram开发的区块链平台&#xff0c;以其高速、低延迟、和高扩展性吸引了大量开发者和项目方。TON链上游戏项目作为一个新兴领域&#xff0c;结合了区块链技术和游戏产业&#xff0c;为用户提供了全新的游戏体验和经济激励。…

精益生产咨询:为企业量身定制的高效能蜕变计划!——张驰咨询

在当今这个快速变化、竞争激烈的市场环境中&#xff0c;企业如何保持持续的竞争优势&#xff0c;提高生产效率&#xff0c;降低成本&#xff0c;同时又能快速响应市场需求&#xff0c;成为了每一个企业家必须面对的重大课题。精益生产&#xff08;Lean Production&#xff09;作…

第5节:Elasticsearch核心概念

我的后端学习笔记大纲 我的ElasticSearch学习大纲 1.Lucene和Elasticsearch的关系: 1.Lucene&#xff1a;最先进、功能最强大的搜索库&#xff0c;直接基于lucene开发&#xff0c;非常复杂&#xff0c;api复杂2.Elasticsearch&#xff1a;基于lucene&#xff0c;封装了许多luc…

跳槽?面试软件测试需要掌握的知识你Get了吗

想从事软件测试相关的工作&#xff0c;立志成为一名优秀的软件测试工程师。 一名优秀的软件测试工程师&#xff0c;需要扎实的专业基础&#xff0c;包括测试相关技术、编程技能、数据库知识、计算机网络、以及操作系统等等。对于没有测试经验的应届生求职者来说&#xff0c;面…