当前位置:网站首页>【2021】腾讯秋招技术岗编程 有效序列的数量
【2021】腾讯秋招技术岗编程 有效序列的数量
2022-04-21 19:44:00 【sigd】


如果序列中数据都不重复,那么这个题目难度会小很多。本文介绍三种解法。
(1)暴力枚举法
暴力枚举子序列左右端点i和j,检查a[i+1]到a[j-1]间是否有比端点更小的值,复杂度O(N^3)。可得20分。
(2)RMQ优化
RMQ(Range Minimum/Maximum Query)可以看成是一种查找结构,能快速找到区间内极值,每次查找的复杂度是O(1)级别。这样可以把上述算法“检查a[i+1]到a[j-1]间是否有比端点更小的值”优化,整个算法复杂度O(N^2),可得70分。
介绍一种骗分技巧,出题人在出大数据的时候,例如上面100000级别数据,经常会出所有数据全部相同的数据点,或者是1,2,3,4.....100000这样的数据点。如果最后实在没有好方法,且时间充足,可编写代码针对这些特殊情况做处理。此方法不保证有效性!!!
(3)单调栈
经验之谈:如果枚举a[i]为序列次小值,找到数据a[i]左右两端第一个比他小得的问题,这是典型的单调栈问题。读者必须掌握单调栈基础用法才可以阅读下面解题思路。
此题目可以考虑枚举第i个元素,a[i]向左找到第一个比a[i]小的值a[k],此时[k,i]区间一定满足条件,
那么是否能继续向左找更小呢?模拟后发现不可以,例如序列1 3 6 5 ,5向左找到3就可以停下来了,以5为次小的序列是(3,6, 5),(1,3,6,5)是不行的。当然也有可能i元素左侧没有比它小的,这样就找不到满足条件子序列。
问题转换为对于a[i],左右两侧是否存在比它小的值。
如果序列中数据都不重复,按上述分析用单调栈双向各做一次,枚举i元素为次小时所有情况即可得到结果。如果数据有重复呢?
对于重复数据,比如1,3,1,4,1,第5个1为次小元素,左边能和它搭配有两个1,而单调栈处理时碰见满足条件的就会停止出栈操作。这样的话需要调整下栈结构,使其不要存储重复元素,但又能知道重复元素有多少个。方法很多,例如入栈元素用结构体,或者用计数器(map)记录栈中相同值元素个数(代码用map)。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,a[100005];
ll ans=0;
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int i,j;
cin>>n;
for(i=1; i<=n; i++)
cin>>a[i];
stack<int>st;
map<int,int>mp;/**< mp计数器,用于记录栈中相同元素的个数,确保栈中元素一定递增,不会有相同值 */
for(i=1; i<=n; i++)
{
while(st.size()&&a[st.top()]>a[i])
{
mp[a[st.top()]]=0;/**< 出栈计数器清零 */
st.pop();
}
if(st.empty())
st.push(i);
else
{
if(a[i]>a[st.top()]) /**< 这个是计算a[i]为次小值,左边比a[i]大的都已经出栈了,栈顶比a[i]小 */
ans++,st.push(i);
else if(a[i]==a[st.top()])
{/**< 处理栈顶和a[i]相同的情况,比如例如这种情况3 3 3 3,第4个3和左边的几个3都能搭配 */
ans+=mp[a[st.top()]];/**< 注意这个时候不要进栈,后面会把栈顶值mp[a[i]]++ */
if(st.size()>1)/**< 1 3 3 3 3,这时第4个3不但和左边3能搭配,还能和1搭配,判断下栈里还有没有比a[i]小的 */
ans++;
}
}
mp[a[i]]++;
}
while(st.size())
st.pop();
for(i=n; i>=1; i--)/**< 反向就无需处理重复元素了 */
{
while(st.size()&&a[st.top()]>=a[i])
st.pop();
if(!st.empty())
ans++;
st.push(i);
}
cout<<ans;
return 0;
}
作者在现场写码时只正向一次单调栈就解决了。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,a[100005];
ll ans=0;
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int i,j;
cin>>n;
for(i=1; i<=n; i++)
cin>>a[i];
stack<int>st;
map<int,ll>mp;/**< mp计数器,用于记录栈中相同元素的个数,确保栈中元素一定递增,不会有相同值 */
for(i=1; i<=n; i++)
{
while(st.size()&&a[st.top()]>a[i])
{/**< 下面这句话实际上是计算a[i]为最小值情况,因为凡是出栈元素,其值均大于a[i]
为什么用mp,比如序列 3 3 3 3 1,此时栈里面只有一个3,但是mp[3]=4,而1和左边的4个3都能构成序列 */
ans+=mp[a[st.top()]];
mp[a[st.top()]]=0;/**< 出栈计数器清零 */
st.pop();
}
if(st.empty())
st.push(i);
else
{
if(a[i]>a[st.top()]) /**< 这个是计算a[i]为次小值,左边比a[i]大的都已经出栈了,栈顶比a[i]小 */
ans++,st.push(i);
else if(a[i]==a[st.top()])
{ /**< 处理栈顶和a[i]相同的情况,比如例如这种情况3 3 3 3,第4个3和左边的几个3都能搭配 */
ans+=mp[a[st.top()]];/**< 注意这个时候不要进栈,后面会把栈顶值mp[a[i]]++ */
if(st.size()>1)/**< 1 3 3 3 3,这时第4个3不但和左边3能搭配,还能和1搭配,判断下栈里还有没有比a[i]小的 */
ans++;
}
}
mp[a[i]]++;
}
cout<<ans;
return 0;
}
版权声明
本文为[sigd]所创,转载请带上原文链接,感谢
https://blog.csdn.net/sigd/article/details/124306504
边栏推荐
猜你喜欢

Source Insight配置及问题汇总

MySQL之2003-Can‘t connect to MySQL server on ‘localhost‘(10038)的解决办法

新冠无情人间有情,欣隆农业保民生共抗疫——慰问抗疫一线及爱老助困送欣隆酵醒鸡蛋蔬菜进社区公益行动

Sorting will be recursive. It's a pity not to learn non recursive

数据分析之数据预处理

码出高效 第七章 并发与多线程

企业跨境电商平台服务解决方案,跨境电子商务贸易业务框架搭建运维

Relationship between deep learning, multi machine and multi card batchsize and learning rate

Static link and dynamic link

一加宣布未来产品将入驻 OPPO 门店,还将首发集团新资源
随机推荐
1075 PAT Judge (25 分)
108. Convert an ordered array into a binary search tree (picture and text merging)
数商云小区物业平台系统解决方案丨轻松管理物业,撬动潜在商机
杰理之复位IO维持电平使用说明【篇】
使用CMake构建/在命令行上构建项目
PE市盈率们之间的区别
PMP考试这些答题思路,你都掌握了吗?
在多文件中C语言中全局变量的重定义
2023年南开大学税务专硕考研上岸前辈备考经验指导
Routing of messages in exchange
“最难就业季“中的大学生就业:本硕过半有着落 高职生成香饽饽
数商云:剖析企业采购管理的现状,推进企业采购模式优化升级
MKL库矩阵乘法
MySQL 视图(详解)
redis安装与配置开机自启
05.原型模式
SAP MTS/MTO/ETO专题之七:Q+M模式前后台操作
vtkjs介绍
数据分析之数据预处理
Linux Centos7 安装MySql8 (简单、实测可行)