最长递增子序列问题

 

目录

最长递增子序列问题

合唱队问题应用:

最长公共子串

LCS:



最长递增子序列问题

问题:给定一个长度为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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值