引言
看这篇题解前建议先看一下点我看题解
废话不多说,直接进入正题
题目:
题目描述
输入格式
输出格式
输入样例
happy
输出样例
1
数据范围
分析
转化问题:最少删除=最多保留=最长上升子序列长度
上一篇题解中我们优化了最长上升子序列,用的是一个g数组存储那些有意义枚举的项
同样,这道题我们也试试用这个方法看行不行
代码如下:
#include<cstdio>
#include <string>
#include<iostream>
#include<algorithm>
using namespace std;
const int NR = 1e5 + 10;
string s;
int g[NR];
int sz = 0;
int main()
{
cin >> s;
int n = s.length();
s = ' ' + s;
for(int i = 1;i <= n;i++)
{
int pos = 1;
while(pos <= sz && g[pos] <= s[i]) pos++;
g[pos] = s[i];
sz = max(pos,sz);
}
cout << n - sz << endl;
return 0;
}
(上面这一段代码和我上一篇题解的样子不太一样,我把F数组删除了,用pos代替就可以了。详细的话看一下上一篇,链接我放到文章开头了)
测试一下,欸~发现没对,有两个数据TLE了,仔细看一下这个数据:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa…………
你会发现这全都是a,老长了。导致超时的原因就是while循环:这些a全在g数组里储存着(因为他们的F数组值不同,是连续递增的,所以都存在g数组里,当然,这里我把F删了),这样一枚举,那循环次数肯定很多,绝对超时。
观察到这道题输入的是一个只含a~z二十六个字母的字符串,对于计算机,已经很少了
我们就拿1 2 3 4四个数举例,假设输入的是只含1 2 3 4四个数的一个数串
我们重新定义一下g数组的含义(这里我把他换成了h,因为含义变了)
//h[i]表示以字符i的ASCII值为结尾的上升子序列的最大长度
那对于我们举的例子来说就是“h[i]表示以1 2 3 4中的第i个为结尾的上升子序列的最大长度”
再来,假设我们现在面对一项其数值为4
那现在能推4的是1 2 3 4四个数(都能推)那么我们只需要考虑着4个值中F数组值最大的!
因为我们选择最优的就能推最优的。这也恰恰是h数组所储存的!
我们看看目前的h数组:
选择F数组值最大的!也就是3,他的F值为4,所以我们面临的这项就是4+1=5
所以我们得到代码:
#include<cstdio>
#include <string>
#include<iostream>
#include<algorithm>
using namespace std;
const int NR = 1e5 + 10;
string s;
int h[128];
//h[i]表示以字符i的ASCII值为结尾的上升子序列的最大长度
int main()
{
cin >> s;
int n = s.length();
s = ' ' + s;
for(int i = 1;i <= n;i++)
{
for(int j = 'a';j <= s[i];j++)
{
h[s[i]] = max(h[s[i]],h[j] + 1);
}
}
int maxn = 0;
for(int i = 'a';i <= 'z';i++)
{
maxn = max(maxn,h[i]);
}
cout << n - maxn << endl;
return 0;
}
点击评测:what???怎么0分,这一改还一分不得了啊?
仔细想想,我们来看这一段代码
for(int j = 'a';j <= s[i];j++)
{
h[s[i]] = max(h[s[i]],h[j] + 1);
}
假设我们面临的字符串是“happy”
把h带进去,会得到:h[h] = max(h[h],h['a' ~'h'] + 1)
前面h['a'~'g']都没有问题,此时运行完h[h]的值应该是1
但是当你运行到h[h] = max(h[h],h[h] + 1),此时h[h]就变成了2,就很奇怪了
所以我们可以用一个变量来存这个事情:mx = max(mx,h[j] + 1)
后面我们赋值给h[i]就可以了!
最终代码:
#include<cstdio>
#include <string>
#include<iostream>
#include<algorithm>
using namespace std;
const int NR = 1e5 + 10;
string s;
int h[128];
//h[i]表示以字符i的ASCII值为结尾的上升子序列的最大长度
int main()
{
cin >> s;
int n = s.length();
s = ' ' + s;
for(int i = 1;i <= n;i++)
{
int maxl = 0;
for(int j = 'a';j <= s[i];j++)
{
maxl = max(maxl,h[j] + 1);
}
h[s[i]] = maxl;
}
int maxn = 0;
for(int i = 'a';i <= 'z';i++)
{
maxn = max(maxn,h[i]);
}
cout << n - maxn << endl;
return 0;
}