一篇最长上升子序列的题解

引言

看这篇题解前建议先看一下点我看题解

点我看题解2

废话不多说,直接进入正题

题目:

题目描述

输入格式

输出格式

输入样例

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值