C++前缀和算法应用:和至少为 K 的最短子数组的原理、源码及测试用例

本文涉及的基础知识点

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频

题目

给你一个整数数组 nums 和一个整数 k ,找出 nums 中和至少为 k 的 最短非空子数组 ,并返回该子数组的长度。如果不存在这样的 子数组 ,返回 -1 。
子数组 是数组中 连续 的一部分。
示例 1:
输入:nums = [1], k = 1
输出:1
示例 2:
输入:nums = [1,2], k = 4
输出:-1
示例 3:
输入:nums = [2,-1,2], k = 3
输出:3
提示:
1 <= nums.length <= 105
-105 <= nums[i] <= 105
1 <= k <= 10^9
#分析

时间复杂度

枚举子数组的结尾i,时间复杂度O(n),利用二分查找,每次枚举O(logn),故总时间复杂度是O(nlogn)。

细节

llSun是num[0,i]的和,vSumIndex 记录[0,j]之和,j取值[-1,i)。假定j0 < j1,且sum[j0] >= sum[j1],那sum[j0,i]小于sum[j1,i]且j0的长度大于j1,所以j0一定不是备选答案,可淘汰。淘汰后如果j0<j1,则sum[j0]一定小于sum[j1]。也就是前缀和和索引都是按升

序排序。sum-sumold >=k ==> sum-k>=sumold ==>sumold <= sum-k 。淘汰的时候:由于是按升序排序,所以sum[j1]不大于等于sum-k,那么sum[j0]也一定不大于等于sum-k。所以找到一个不符合,就可停止了。
#核心代码
class Solution {
public:
int shortestSubarray(vector& nums, int k) {
m_c = nums.size();
m_vRet.assign(m_c, -1);
vector<pair<long long, int>> vSumIndex = { {0,-1} };
long long llSum = 0;
m_vRet.assign(m_c, INT_MAX);
for (int i = 0; i < m_c; i++)
{
llSum += nums[i];
//sum-sumold >=k ==> sum-k>=sumold ==>sumold <= sum-k
//由于sum和index都是升序,所以可以二分
auto it = std::upper_bound(vSumIndex.begin(), vSumIndex.end(), llSum - k, []( const long long ll,const pair<long, int>& pi)
{
return ll < pi.first;
});
if (vSumIndex.begin() != it)
{
m_vRet[i] = i - std::prev(it)->second;
}
while (vSumIndex.size() && (vSumIndex.back().first >= llSum))
{
vSumIndex.pop_back();
}
vSumIndex.emplace_back(llSum, i);
}
const int iRet = *std::min_element(m_vRet.begin(), m_vRet.end());
return (INT_MAX == iRet) ? -1 : iRet;
}
int m_c;
vector m_vRet;
};

测试用例

m_vRet是多余的,是为了方便排错。
template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
assert(v1[i] == v2[i]);
}
}

template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}
class Solution {
public:
int shortestSubarray(vector& nums, int k) {
m_c = nums.size();
m_vRet.assign(m_c, -1);
vector<pair<long long, int>> vSumIndex = { {0,-1} };
long long llSum = 0;
m_vRet.assign(m_c, INT_MAX);
for (int i = 0; i < m_c; i++)
{
llSum += nums[i];
//sum-sumold >=k ==> sum-k>=sumold ==>sumold <= sum-k
//由于sum和index都是升序,所以可以二分
auto it = std::upper_bound(vSumIndex.begin(), vSumIndex.end(), llSum - k, []( const long long ll,const pair<long, int>& pi)
{
return ll < pi.first;
});
if (vSumIndex.begin() != it)
{
m_vRet[i] = i - std::prev(it)->second;
}
while (vSumIndex.size() && (vSumIndex.back().first >= llSum))
{
vSumIndex.pop_back();
}
vSumIndex.emplace_back(llSum, i);
}
const int iRet = *std::min_element(m_vRet.begin(), m_vRet.end());
return (INT_MAX == iRet) ? -1 : iRet;
}
int m_c;
vector m_vRet;
};

错误做法

auto it = std::upper_bound(vSumIndex.begin(), vSumIndex.end(), std::make_pair(llSum - k,0));
我们期望:
返回第一个 first大于llSum-k的值。
实际上,返回第一个符合以下条件之一的迭代器:
一,first大于llSum-k
二,first等于llSum-k,second>0
解决方法:将0换成m_c,这样条件二,就永远不会成立。也可以换成INT_MAX。修改后的代码如下:
auto it = std::upper_bound(vSumIndex.begin(), vSumIndex.end(), std::make_pair(llSum - k,m_c));

2023年3月分的旧版

仅供参考
template
bool Less(const std::pair<Class1, int>& p, Class1 iData)
{
return p.first < iData;
}

template
bool Greater(const std::pair<Class1, int>& p, Class1 iData)
{
return p.first > iData ;
}

class Solution {
public:
int shortestSubarray(vector& nums, int k) {
int iMinLen = INT_MAX;
std::vector<std::pair<long, int>> vQue;
vQue.emplace_back(0, -1);
long long llSum = 0;
for (int i = 0; i < nums.size(); i++)
{
llSum += nums[i];
int iLessEqualNum = std::lower_bound(vQue.begin(), vQue.end(), llSum - k + 1, Less) - vQue.begin();
if (iLessEqualNum > 0 )
{
iMinLen = min(iMinLen, i - vQue[iLessEqualNum - 1].second);
}
while (vQue.size() && (llSum <= vQue.back().first))
{
vQue.pop_back();
}
vQue.emplace_back(llSum, i);
}
return (INT_MAX == iMinLen) ? -1 : iMinLen;
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《闻缺陷则喜算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

鄙人想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
墨家名称的来源:有所得以墨记之。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17

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

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

相关文章

2023年【建筑架子工(建筑特殊工种)】考试内容及建筑架子工(建筑特殊工种)找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 建筑架子工(建筑特殊工种)考试内容是安全生产模拟考试一点通生成的&#xff0c;建筑架子工(建筑特殊工种)证模拟考试题库是根据建筑架子工(建筑特殊工种)最新版教材汇编出建筑架子工(建筑特殊工种)仿真模拟考试。2023…

Mybatis对数据库进行增删查改以及单元测试

这篇写的草率了&#xff0c;是好几天前学到&#xff0c;以后用来自己复习 UserInfo import lombok.Data;Data public class UserInfo {private int id;private String name;private int age;private String email;//LocalDateTime可用于接收 时间}Mapper UserMapper pack…

Python-flask高级使用

文章目录 一.Python-flask使用数据库第一步&#xff1a;首先安装包安装 flask-sqlalchemy (用于ORM&#xff09;&#xff1a;安装 flask-migrate (用于数据迁移)&#xff1a;安装 pymysql (MySQL驱动)&#xff1a; 第二步:在__init__ 配置第三步&#xff1a;插件管理第一步&…

react+ts手写cron表达式转换组件

前言 最近在写的一个分布式调度系统&#xff0c;后端同学需要让我传入cron表达式&#xff0c;给调度接口传参。我去了学习了解了cron表达式的用法&#xff0c;发现有3个通用的表达式刚好符合我们的需求&#xff1a; 需求 每天 xx 的时间&#xff1a; 0 11 20 * * ? 上面是…

通过内网穿透技术实现USB设备共享(USB Redirector)逆向共享

文章目录 前言1. 安装下载软件1.1 内网安装使用USB Redirector1.2 下载安装cpolar内网穿透 2. 完成USB Redirector服务端和客户端映射连接3. 设置固定的公网地址 前言 USB Redirector是一款方便易用的USB设备共享服务应用程序&#xff0c;它提供了共享和访问本地或互联网上的U…

Python 机器学习入门之K-Means聚类算法

系列文章目录 第一章 Python 机器学习入门之线性回归 K-Means聚类算法 系列文章目录前言一、K-Means简介1、定义2、例子3、K-Means与KNN 二、 K-Means实现1、步骤2、优化2.1 初始化优化之K-Means2.2 距离优化之elkan K-Means 三、优缺点1、优点2、缺点 前言 学完K近邻算法&a…

【Java 进阶篇】JavaScript 动态表格案例

在这篇博客中&#xff0c;我们将深入了解JavaScript如何创建和操作动态表格。我们将从头开始构建一个动态表格&#xff0c;并逐步添加各种功能&#xff0c;使其能够实现数据的添加、删除和编辑。这个示例将有助于理解如何在前端开发中使用JavaScript创建交互性强大的表格。 准…

Linux | vim的入门手册

目录 前言 一、什么是vim 二、vim编辑器的模式 1、插入模式 &#xff08;1&#xff09;用vim打开文件 &#xff08;2&#xff09;进入插入模式 2、默认模式 &#xff08;1&#xff09;光标移动 &#xff08;2&#xff09;复制、粘贴与剪切操作 &#xff08;3&#x…

uniapp checkbox样式失效,选中框选中按钮不显示

找了很多方法 最后网上一个博主找到了解决方法 在项目的main.css里面 如果你不知道你的css样式在哪个文件夹 直接全局搜索‘ 找到注释两个地方 第一个 checkbox::before 找到这一行 注释箭头指的地方就可以 第二个 checkbox .uni-checkbox-input::before, 注释这两个地方…

垃圾邮件(短信)分类算法实现 机器学习 深度学习 计算机竞赛

文章目录 0 前言2 垃圾短信/邮件 分类算法 原理2.1 常用的分类器 - 贝叶斯分类器 3 数据集介绍4 数据预处理5 特征提取6 训练分类器7 综合测试结果8 其他模型方法9 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 垃圾邮件(短信)分类算…

腾讯云服务器上行带宽和下行带宽速度表

腾讯云服务器公网带宽下载速度计算&#xff0c;1M公网带宽下载速度是128KB/秒&#xff0c;5M带宽下载速度是512KB/s&#xff0c;腾讯云10M带宽下载速度是1.25M/秒&#xff0c;腾讯云百科txybk.com来详细说下腾讯云服务器不同公网带宽实际下载速度以及对应的上传速度对照表&…

Linux篇 五、Ubuntu与Linux板卡建立NFS服务

Linux系列文章目录 一、香橙派Zero2设置开机连接wifi 二、香橙派Zero2获取Linux SDK源码 三、香橙派Zero2搭建Qt环境 四、Linux修改用户名 文章目录 Linux系列文章目录前言一、连接到局域网互ping测试 二、安装NFS服务配置NFS更新exports配置三、板卡安装NFS客户端四、板卡临时…