2022-03-05每日刷题打卡

2022-03-05每日刷题打卡

力扣——每日一题

521. 最长特殊序列 Ⅰ

给你两个字符串 a 和 b,请返回 这两个字符串中 最长的特殊序列 。如果不存在,则返回 -1 。

「最长特殊序列」 定义如下:该序列为 某字符串独有的最长子序列(即不能是其他字符串的子序列) 。

字符串 s 的子序列是在从 s 中删除任意数量的字符后可以获得的字符串。

例如,“abc” 是 “aebdc” 的子序列,因为删除 “aebdc” 中斜体加粗的字符可以得到 “abc” 。 “aebdc” 的子序列还包括 “aebdc” 、 “aeb” 和 “” (空字符串)。

示例 1:

输入: a = “aba”, b = “cdc”
输出: 3
解释: 最长特殊序列可为 “aba” (或 “cdc”),两者均为自身的子序列且不是对方的子序列。

这题一开始,想着是先求最长公共子序列,然后拿最长的那个字符串长度减去公共序列的长度。结果我万万没想到这题居然是个脑筋急转弯。

你要独有的最长子序列是吧,独有就是我有你没有是吧,那我这个字符串整体要是比你长,我是不是就不可能是你的子序列了,而且我长度比你长,是不是就是最长了,那我自己就是这个独有的最长子序列,直接返回我自身的长度即可。

(这题出的真。。。他娘的好啊)

class Solution {
public:
    int findLUSlength(string a, string b) {
        if(a==b)return -1;
        int n=a.size(),m=b.size();
        if(n>m)return n;
        return m;
    }
};

代码源——div2每日一题

你有n个任务,其中第ii个任务,在si开始,ei时刻结束,如果做这个任务,你能获得wi的收益。

但是你在一个时刻只能做一个任务,问选择哪些任务,能让你的收益尽量大。

注意:你在上一个任务结束后马上开始下一个任务是可以的。

输入格式

第一行一个整数n。

接下来n行,每行三个整数si,ei,wi。

输出格式

一个数,表示答案。

样例输入

3
1 3 100
2 4 199
3 5 100

样例输出

200

数据规模

对于所有数据,保证1≤n≤103,1≤si<ei≤103,1≤wi≤10^5

最长上升子序列同等做法,准备一个n*3的二维数组来接受一个任务的起始时间,结束时间和价值。存入二维数组后记得要对它排序,题目这里给的数据并不是有序的,我们按照任务的起始时间递增排序,如果起始时间相同就按照结束时间递增排序,都一样就按照价值递增排序。然后就是最长上升子序列了,每次到一个任务,回头看看之前做过的任务,有没有结束时间能和自己的开始时间接上的,如果有,就比较是自身的价值高,还是当前任务的价值+之前任务的价值高,两者中取较大的。在此过程中拿一个res记录最大值,最后输出res即可。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>

typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1010;
ll s[N], w[N], e[N];
PII f[N];

bool cmp(vector<ll>a, vector<ll>b)
{
	if (a[0] != b[0])return a[0] < b[0];
	else if (a[1] != b[1])return a[1] < b[1];
	return a[2] < b[2];
}

int main()
{
	int n, m;
	cin >> n;
	vector<vector<ll>>v(n, vector<ll>(3));
	for (int i = 0; i < n; i++)
	{
		cin >> v[i][0] >> v[i][1] >> v[i][2];
	}
	sort(v.begin(), v.end(), cmp);
	f[0].first = v[0][1];
	f[0].second = v[0][2];
	ll res = f[0].second;
	for (int i = 1; i < n; i++)
	{
		ll ans = 0;
		f[i].first = v[i][1];
		f[i].second = v[i][2];
		for (int j = i - 1; j >= 0; j--)
		{
			if (v[i][0] >= f[j].first)
			{
				f[i].second = max(f[i].second, f[j].second + v[i][2]);
				
			}
		}
		res = max(res, f[i].second);
	}
	cout << res << endl;
	
	return 0;
}

但是这做法最多只能过10^5,再大就要超时了,从大佬那里学来一个更nb的做法。

设置dp数组f,f[i]为:当任务的结束时间为i时,所能获得的最大价值。在接收数据时,按照任务的结束时间分类存储在v数组里(以数对形式存,first是开始时间,second是价值)。同时记录一下所有任务中最大的结束时间。

我们从下标i=1开始更新f数组,遍历过程中,根据结束时间为i,去之前分类存好任务的数组里去找,找结束时间为i的任务,然后状态转移方程:f[i]=max(f[i],v[v[i] [j].first]+v[i] [j].second);j是以i为结束时间的第j个任务。以此更新f数组。最后返回f[m];

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>

typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1000010;
ll s[N], e[N], w[N], f[N];
vector<PII>v[N];

int main()
{
	ll n, m = 0;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> s[i] >> e[i] >> w[i];
		v[e[i]].push_back({ s[i],w[i] });
		m = max(e[i], m);
	}
	for (int i = 1; i <= m; i++)
	{
		f[i] = f[i - 1];
		for (auto j : v[i])
		{
			f[i] = max(f[i], f[j.first] + j.second);
		}
	}
	cout << f[m];
	

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值