关闭

最长递增子序列&&最长公共子序列&&最长公共子串

61人阅读 评论(0) 收藏 举报
分类:
最长递增子序列A
给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)
例如:给定一个长度为8的数组A{1,3,5,2,4,6,7,8},则其最长的单调递增子序列为{1,2,4,6,7,8},长度为6.



输入描述:

第一行包含一个整数T,代表测试数据组数。 对于每组测试数据: N-数组的长度 a1 a2 ... an (需要计算的数组) 保证: 1<=N<=3000,0<=ai<=MAX_INT.



输出描述:

对于每组数据,输出一个整数,代表最长递增子序列的长度。


输入例子:
2
7
89 256 78 1 46 78 8
5
6 4 8 2 17

输出例子:
3

3

采用O(nlogn)的优化算法,代码如下

算法核心主要思想:采用一个辅助数组,来存放最长递增子序列;更新策略为(1)对于一个新数据,在辅助数组中已经有的序列中寻找第一个大于当前数据的元素并把它替换(2)若新数据大于辅助数组中最大的元素,则扩张辅助数组一次单位。重复上述过程直到结束,由于辅助数组即为最长递增子序列的长度,故返回辅助数组长度即可。遍历数据的复杂度为O(n),更新策略采用二分查找的方法,算法复杂度为O(logn),故总的算法复杂度为O(nlogn)

#include<iostream>
using namespace std;
int er(int *a,int time)
    {//算法核心    
    if(a==NULL||time<0)
    return 0;
    int l,r,m,right=0;
    int *end=new int[time];
    end[0]=a[0];
    for(int i=1;i<time;i++)
        {
        l=0;r=right;
         while(l<=r)
             {
             m=(l+r)/2;
             if(a[i]>end[m])
                 l=m+1;
             else
                 r=m-1;
         }
        end[l]=a[i];
        right=l>right?l:right;
    }
    return right+1;
}
int main()
    {
    int n,time;
    while(cin>>n)
        {
        while(n--&&cin>>time)
            {
            int *a=new int[time];
            for(int i=0;i<time;i++)
                cin>>a[i];
            cout<<er(a,time)<<endl;
        }
        
    }
    return 0;
}

最长递增子序列B
给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)
例如:给定一个长度为8的数组A{1,3,5,2,4,6,7,8},则其最长的单调递增子序列为{1,2,4,6,7,8},长度为6.



输入描述:

第一行包含一个整数T,代表测试数据组数。 对于每组测试数据: N-数组的长度 a1 a2 ... an (需要计算的数组) 保证: 1<=N<=3000,0<=ai<=MAX_INT.



输出描述:

对于每组数据,输出一个整数序列,代表最长递增子序列。 若有多组最长上升子序列,输出第一组。 保证:1<=T<=20,1<=N<=3000,0<=ai<=MAX_INT.


输入例子:
2
7
89 256 78 1 46 78 8
5
6 4 8 2 17

输出例子:
1 46 78
6 8 17
由于要求有多个最长子序列则输出第一个,故第一题中的方法不适用。自己采用新建一个类 类中包含2个元素 length和value分别为当前位置最长递增子序列的长度和上一个与之比较元素的下标索引

class L
{
public:
	int length;当前位置最长递增子序列的长度</span>
	int index;上一个与之比较元素的下标索引</span>
};



上面为对应过程,遍历每一个元素并更新对应length和index代码如下

#include<iostream>
#include<stack>
using namespace std;
class L
{
public:
	int length;
	int index;
};
void vd(int *a, int n)
{
	if (a == NULL || n < 0)return;
	L *p = new L[n];//对应的辅助数组
	stack<int> s;
	for (int i = 0; i < n; i++)
	{
		p[i].length = 1;
		p[i].index = -1;
	}
	int max = 0;
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = i + 1; j < n; j++)
		{
			if (a[j]>a[i])
			{       //辅助数组的更新
				int temp = p[j].length;
				if (p[i].length + 1>temp)
				{
					p[j].length = p[i].length + 1;
					p[j].index = i;
				}
				if (p[j].length > max)//记录最长子序列的长度
					max = p[j].length;
			}
		}
	}
	int index = 0;
	for (int i = 0; i < n; i++)
	{
		if (p[i].length == max)
		{//找出第一个最长子序列,并记录其下标
			index = i;
			break;
		}
	}
	L temp = p[index];
	int t = index;//输出子序列
	while (temp.index>=0)
	{
		s.push(a[t]);
		t = temp.index;
		temp = p[temp.index];	
	}
	s.push(a[t]);
	while (s.size()!=1)
	{
		cout << s.top() << ' ';
		s.pop();
	}
	cout << s.top()<< endl;
	s.pop();
}
int main()
{
	int num, time;
	while (cin>>num)
	{
		while (num--&&cin>>time)
		{
			int *a = new int[time];
			for (int i = 0; i < time; i++)
				cin >> a[i];
			vd(a,time);
		}
	}
}

题目描述

对于两个字符串,请设计一个高效算法,求他们的最长公共子序列的长度,这里的最长公共子序列定义为有两个序列U1,U2,U3...Un和V1,V2,V3...Vn,其中Ui&ltUi+1,Vi&ltVi+1。且A[Ui] == B[Vi]。

给定两个字符串AB,同时给定两个串的长度nm,请返回最长公共子序列的长度。保证两串长度均小于等于300。

测试样例:
"1A2C3D4B56",10,"B1D23CA45B6A",12
返回:6
int findLCS(string a, int n, string b, int m) {
	int **dp = new int*[n+1];//dp[i][j]表示a以i-1位置结尾b以j-1位置结尾时的最长公共子串长度
	for (int i = 0; i<n+1; i++)
		dp[i] = new int[m+1];
    for(int i=0;i<n+1;i++)dp[i][0]=0;
    for(int j=0;j<m+1;j++)dp[0][j]=0;
	for (int i = 1; i<n+1; i++)
	for (int j = 1; j<m+1; j++)
	{
		if (a[i-1] == b[j-1])
		{
		 dp[i][j] = dp[i - 1][j - 1] + 1;
		}
		else 
            dp[i][j] = dp[i - 1][j - 1];
        dp[i][j] = dp[i][j]>dp[i - 1][j] ? dp[i][j] : dp[i - 1][j];
		dp[i][j] = dp[i][j]>dp[i][j - 1] ? dp[i][j] : dp[i][j - 1];
	}
 
return dp[n][m];
}

最长公共子串

对于两个字符串,请设计一个时间复杂度为O(m*n)的算法(这里的m和n为两串的长度),求出两串的最长公共子串的长度。这里的最长公共子串的定义为两个序列U1,U2,..Un和V1,V2,...Vn,其中Ui + 1 == Ui+1,Vi + 1 == Vi+1,同时Ui == Vi。

给定两个字符串AB,同时给定两串的长度nm

测试样例:
"1AB2345CD",9,"12345EF",7
返回:4
公共子串要求为连续 与上一题有些不同
class LongestSubstring {
public:
    int findLongest(string a, int n, string b, int m) {
        int dp[n+1][m+1];
        for(int i=0;i<n+1;i++)
        for(int j=0;j<m+1;j++)
            dp[i][j]=0;
        int max=-1;//用于统计最长的子串长度
        for(int i=1;i<n+1;i++)
            for(int j=1;j<m+1;j++)
            {
            if(a[i-1]==b[j-1])//只有2个字符相等时才增加
                dp[i][j]=dp[i-1][j-1]+1;
            if(dp[i][j]>max)max=dp[i][j];
        }
        return max;
    }
};




0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:25976次
    • 积分:1504
    • 等级:
    • 排名:千里之外
    • 原创:126篇
    • 转载:41篇
    • 译文:0篇
    • 评论:5条
    最新评论