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;
}