目录
最长递增子序列问题
问题:给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)。例如:给定一个长度为6的数组A{5, 6, 7, 1, 2, 8},则其最长的单调递增子序列为{5,6,7,8},长度为4.
dp法:
设长度为N的数组为{a0,a1, a2, ...an-1),则假定以aj结尾的数组序列的最长递增子序列长度为L(j),则L(j)={ max(L(i))+1, i<j且a[i]<a[j] }。也就是说,我们需要遍历在j之前的所有位置i(从0到j-1),找出满足条件a[i]<a[j]的L(i),求出max(L(i))+1即为L(j)的值。最后,我们遍历所有的L(j)(从0到N-1),找出最大值即为最大递增子序列。时间复杂度为O(N^2)。
int main()
{
int n;
vector<int>num;
cin >> n;
vector<int>inc_cnt(n,1);
int t;
for (int i = 0; i < n; ++i)
{
cin >> t;
num.push_back(t);
}
for(int i = 1;i<n;++i)
for (int j = i - 1; j >= 0; --j)
{
if (num[i] > num[j] && inc_cnt[i] < inc_cnt[j] + 1)
inc_cnt[i] = inc_cnt[j] + 1;
}
int max_len = 1;
for (int i = 1; i<n; ++i)
{
if (max_len < inc_cnt[i])
max_len = inc_cnt[i];
}
cout << max_len << endl;
return 0;
}
合唱队问题应用:
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足存在i(1<=i<=K)使得T1<T2<......<Ti-1<Ti>Ti+1>......>TK。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
首先计算每个数在最大递增子串中的位置
186 186 150 200 160 130 197 200 quene
1 1 1 2 2 1 3 4 递增计数
然后计算每个数在反向最大递减子串中的位置--->计算反向后每个数在最大递增子串中的位置
200 197 130 160 200 150 186 186 反向quene
1 1 1 2 3 2 3 3 递减计数
然后将每个数的递增计数和递减计数相加
186 186 150 200 160 130 197 200 quene
1 1 1 2 2 1 3 4 递增计数
3 3 2 3 2 1 1 1 递减计数
4 4 3 5 4 2 4 5 每个数在所在队列的人数+1(自己在递增和递减中被重复计算)
如160这个数
在递增队列中有2个人数
150 160
在递减队列中有2个人数
160 130
那么160所在队列中就有3个人
150 160 130
每个数的所在队列人数表达就是这个意思
总人数 - 该数所在队列人数 = 需要出队的人数
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void incre_cnt(vector<int>&arr, vector<int>&cnt)
{
for (int i = 1; i<arr.size(); i++)
for (int j = i - 1; j >= 0; j--)
{
if (arr[j]<arr[i] && cnt[i]<cnt[j]+1)
cnt[i] = cnt[j] + 1;
}
}
int main()
{
int n;
while(cin>>n)//牛客输入 流式
{
vector<int>num;
vector<int>inc_cnt(n, 1);
vector<int>dec_cnt(n, 1);
int temp;
for (int i = 0; i<n; i++)
{
cin >> temp;
num.push_back(temp);
}
incre_cnt(num, inc_cnt);
reverse(num.begin(), num.end());
incre_cnt(num, dec_cnt);
reverse(dec_cnt.begin(), dec_cnt.end());
int max_queue = 0;
for (int i = 0; i < n; ++i)
{
if (dec_cnt[i] + inc_cnt[i] > max_queue)
{
max_queue = dec_cnt[i] + inc_cnt[i];
}
}
cout << n - max_queue + 1 << endl;
}
return 0;
}
最长公共子串
//最长公共子串
string LCsubstring(string s1, string s2)
{
int len1 = s1.size();
int len2 = s2.size();
int record[100][100] = {0};
int max = 0, indexx = 0, indexy = 0;
for(int i = 1;i<len1;++i)
for (int j = 1; j < len2; j++)
{
if (s1[i - 1] == s2[j - 1])
{
record[i][j] = record[i - 1][j - 1] + 1;
if (record[i][j] > max)
{
max = record[i][j];
indexx = i;
indexy = j;
}
}
else
record[i][j] = 0;
}
string s;
for (int i = indexx - max; i <= max; i++)
{
s += s1[i];
}
return s;
}
LCS:
https://blog.csdn.net/orbit/article/details/6717125
int main()
{
string x = "abcdefghijklmnopq";
string y = "acefhjklmqddenfvj";
int const xlen = x.length();
int const ylen = y.length();
int c[100][100];
int n[100][100];//0-left 1-top 2-left-top
for (int i = 0; i <= xlen; i++)
c[i][0] = 0;
for (int j = 0; j <= ylen; j++)
c[0][j] = 0;
for (int i = 1; i <= xlen; i++)
{
for (int j = 1; j <= ylen; j++)
{
if (x.at(i - 1) == y.at(j - 1))
{
c[i][j] = c[i - 1][j - 1] + 1;
n[i - 1][j - 1] = 2;
}
else
{
c[i][j] = c[i - 1][j]>c[i][j - 1] ? c[i - 1][j] : c[i][j - 1];
n[i - 1][j - 1] = c[i - 1][j] >= c[i][j - 1] ? 1 : 0;
}
}
}
int i = xlen - 1;
int j = ylen - 1;
string s;
while (1)
{
if (i == 0 || j == 0)
{
if (n[i][j] == 2)
s += x.at(i);
break;
}
if (n[i][j] == 0)
{
j--;
}
else if (n[i][j] == 1)
{
i--;
}
else
{
s += x.at(i);
i--;
j--;
}
}
for (i = s.length() - 1; i >= 0; i--)
cout << s.at(i) << " ";
return 0;
}
参考:
https://www.nowcoder.com/questionTerminal/6d9d69e3898f45169a441632b325c7b4?f=discussion