C++单调向量算法应用:所有子数组中不平衡数字之和

简介: C++单调向量算法应用:所有子数组中不平衡数字之和

涉及知识点

单调向量

题目

一个长度为 n 下标从 0 开始的整数数组 arr 的 不平衡数字 定义为,在 sarr = sorted(arr) 数组中,满足以下条件的下标数目:

0 <= i < n - 1 ,和

sarr[i+1] - sarr[i] > 1

这里,sorted(arr) 表示将数组 arr 排序后得到的数组。

给你一个下标从 0 开始的整数数组 nums ,请你返回它所有 子数组 的 不平衡数字 之和。

子数组指的是一个数组中连续一段 非空 的元素序列。

示例 1:

输入:nums = [2,3,1,4]

输出:3

解释:总共有 3 个子数组有非 0 不平衡数字:

  • 子数组 [3, 1] ,不平衡数字为 1 。
  • 子数组 [3, 1, 4] ,不平衡数字为 1 。
  • 子数组 [1, 4] ,不平衡数字为 1 。
    其他所有子数组的不平衡数字都是 0 ,所以所有子数组的不平衡数字之和为 3 。
    示例 2:
    输入:nums = [1,3,3,3,5]
    输出:8
    解释:总共有 7 个子数组有非 0 不平衡数字:
  • 子数组 [1, 3] ,不平衡数字为 1 。
  • 子数组 [1, 3, 3] ,不平衡数字为 1 。
  • 子数组 [1, 3, 3, 3] ,不平衡数字为 1 。
  • 子数组 [1, 3, 3, 3, 5] ,不平衡数字为 2 。
  • 子数组 [3, 3, 3, 5] ,不平衡数字为 1 。
  • 子数组 [3, 3, 5] ,不平衡数字为 1 。
  • 子数组 [3, 5] ,不平衡数字为 1 。
    其他所有子数组的不平衡数字都是 0 ,所以所有子数组的不平衡数字之和为 8 。
    参数范围
    1 <= nums.length <= 1000
    1 <= nums[i] <= nums.length

分析

时间复杂度

O(n*logn),共五步,四步是是O(n),一步是O(nlogn),故总时间复杂度是O(nlogn)。

排在首位

左边没有数小于等于nums[i],右边没有数据小于nums[i]。

原理

排序时,相同的数字相同顺序不变。依次枚举nums个元素,再计算所有子数组的不平衡数之和。如果左边有数等于nums[i]或nums[i]-1,则nums[i]一定不是不平衡数字。处理nums[i]时,包括nums[i]的子数组[l,r],l其取值范围为(-1,i],r取值范围为[i,m_c)。令l1是nums[l1]nums[i]或nums[l1]+1nums[i],l1取值范围为(-1,i)如果有多个l1,取最大值。令r1取值范围为(i,m_c),令nums[r1]==nums[i]-1,如果有多个r1,取最小值。如果l1不存在,取-1;如果r1不存在取m_c。如果l取[0,il]或r取[r1,m_c),则nums[i]一定不是平衡数。

条件一 取[0,il]或r取[r1,m_c)
条件二 排在首位
情况一 条件一成立 条件二一定不成立 一定不是不平衡数
情况二 条件一不成立 条件二成立 一定不是不平衡数
情况二 条件一不成立 条件二不成立 不平衡数

由于条件一和条件二不可能同时成立,所以情况二,可以简化为:条件二成立。

变量解释

num1 情况二和情况三
num2 情况二

单调向量

如果l11 < l12,且nums[l11] >= nums[l12],则l11被淘汰。这意味者:qLeft是单调递增,方便使用二分查找

步骤

一,计算l1。

二,计算r1。

三,计算l2。

四,计算r2。

五,枚举nums[i]的不平衡数。

代码

class Solution {
public:
int sumImbalanceNumbers(vector& nums) {
m_c = nums.size();
const int iMaxValue = *std::max_element(nums.begin(), nums.end());
vector vLeftRange(m_c),vRightRange(m_c);
{
vector vLeft(iMaxValue + 1, -1);
for (int i = 0; i < m_c; i++)
{
vLeftRange[i] = max(vLeft[nums[i]], vLeft[nums[i] - 1]);
vLeft[nums[i]] = i;
}
}
{
vector vRight(iMaxValue + 1, nums.size());
for (int i =m_c-1 ; i >= 0 ; i-- )
{
vRightRange[i] = vRight[nums[i]-1];
vRight[nums[i]] = i;
}
}
vector vLeftRange2(m_c), vRightRange2(m_c);
{
vector<pair<int, int>> qLeft;
for (int i = 0; i < m_c; i++)
{
auto it1 = std::upper_bound(qLeft.begin(), qLeft.end(), std::make_pair(nums[i] + 1, -1));
int left = (qLeft.begin() == it1) ? -1 : std::prev(it1)->second;
vLeftRange2[i] = left;
while (qLeft.size() && (qLeft.back().first >= nums[i]))
{
qLeft.pop_back();
}
qLeft.emplace_back(nums[i], i);
}
}
{
vector<pair<int, int>> qRight;
for (int i = m_c - 1; i >= 0; i–)
{
auto it2 = std::upper_bound(qRight.begin(), qRight.end(), std::make_pair(nums[i], -1));
auto right = (qRight.begin() == it2) ? m_c : std::prev(it2)->second;
vRightRange2[i] = right;
while (qRight.size() && (qRight.back().first >= nums[i]))
{
qRight.pop_back();
}
qRight.emplace_back(nums[i], i);
}
}
int iRet = 0;
for (int i = 0; i < m_c; i++)
{
int num1 = (i - vLeftRange[i]) * (vRightRange[i] - i);//左边不包括nums[i]和nums[i]-1,右边不包括nums[i]的数量
int num2 = (i - vLeftRange2[i]) * (vRightRange2[i] - i);//左边全部都比他大,右边大于等于,也就是排到最左边
iRet += num1 - num2;
}
return iRet;
}
int m_c;
};

核心代码

测试

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);
}
int main()
{
Solution slu;
vector nums = {2,3,1,3 };
int res;
res = slu.sumImbalanceNumbers(nums);
Assert(3 ,res);
//CConsole::Out(res);

}

2023年8月旧代码一

class Solution {
public:
int sumImbalanceNumbers(vector& nums) {
m_c = nums.size();
int iRet = 0;
for (int i = 0; i < m_c; i++)
{
int iMin = nums[i], iMax = nums[i];
int iBalanceNum = 0;
std::unordered_set mVis;
mVis.emplace(nums[i]);
for (int j = i+1; j < m_c; j++)
{
const int& n = nums[j];
if (mVis.count(n))
{
iRet += iBalanceNum;
continue;
}
if (n < iMin)
{
if (!mVis.count(n + 1))
{
iBalanceNum++;
}
iMin = n;
}
else if (n > iMax)
{
if (!mVis.count(n - 1))
{
iBalanceNum++;
}
iMax = n;
}
else
{
if (mVis.count(n - 1)&& mVis.count(n + 1))
{
iBalanceNum–;
}
if (mVis.count(n - 1) || mVis.count(n + 1))
{
}
else
{
iBalanceNum++;
}
}
iRet += iBalanceNum;
mVis.emplace(n);
}
}
return iRet;
}
int m_c;
};

2023年8月旧代码二

class Solution {
public:
int sumImbalanceNumbers(vector& nums) {
m_c = nums.size();
int mVis[1001] = { 0 };
int iRet = 0;
for (int i = 0; i < m_c; i++)
{
int iMin = nums[i], iMax = nums[i];
int iBalanceNum = 0;
memset(mVis, 0, sizeof(mVis));
mVis[nums[i]]= true;
for (int j = i+1; j < m_c; j++)
{
const int& n = nums[j];
if (mVis[n])
{
iRet += iBalanceNum;
continue;
}
if (n < iMin)
{
if (!mVis[n + 1])
{
iBalanceNum++;
}
iMin = n;
}
else if (n > iMax)
{
if (!mVis[n - 1])
{
iBalanceNum++;
}
iMax = n;
}
else
{
if (mVis[n - 1] && mVis[n + 1])
{
iBalanceNum–;
}
if (mVis[n - 1] || mVis[n + 1])
{
}
else
{
iBalanceNum++;
}
}
iRet += iBalanceNum;
mVis[n]=true;
}
}
return iRet;
}
int m_c;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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


相关文章
|
12月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
233 2
|
存储 算法 C++
Windows共享文件:探秘C++实现的B树索引算法奇境
在数字化时代,Windows共享文件的高效管理至关重要。B树算法以其自平衡多路搜索特性,在文件索引与存储优化中表现出色。本文探讨B树在Windows共享文件中的应用,通过C++实现具体代码,展示其构建文件索引、优化数据存储的能力,提升文件检索效率。B树通过减少磁盘I/O操作,确保查询高效,为企业和个人提供流畅的文件共享体验。
|
7月前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
275 11
|
12月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
286 17
|
11月前
|
存储 机器学习/深度学习 算法
基于 C++ 的局域网访问控制列表(ACL)实现及局域网限制上网软件算法研究
本文探讨局域网限制上网软件中访问控制列表(ACL)的应用,分析其通过规则匹配管理网络资源访问的核心机制。基于C++实现ACL算法原型,展示其灵活性与安全性。文中强调ACL在企业与教育场景下的重要作用,并提出性能优化及结合机器学习等未来研究方向。
274 4
|
10月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
250 0
|
11月前
|
机器学习/深度学习 存储 算法
基于 C++ 布隆过滤器算法的局域网上网行为控制:URL 访问过滤的高效实现研究
本文探讨了一种基于布隆过滤器的局域网上网行为控制方法,旨在解决传统黑白名单机制在处理海量URL数据时存储与查询效率低的问题。通过C++实现URL访问过滤功能,实验表明该方法可将内存占用降至传统方案的八分之一,查询速度提升约40%,假阳性率可控。研究为优化企业网络管理提供了新思路,并提出结合机器学习、改进哈希函数及分布式协同等未来优化方向。
302 0
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
261 4
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
485 12