最大子序列、最长递增子序列、最长公共子串、最长公共子序列

#include<iostream>
#include<limits>
#include<vector>
#include<stack>
#include<string>


#define LEFTUP 0
#define LEFT 1
#define UP 2

using namespace std;

//最大子串
int maxSubSum(const vector<int> & arr,int &begin,int &end) {
	int maxSum = numeric_limits<int>::min();
	int curSum = 0;
	int newbegin = 0;
	for(int i = 0; i<arr.size(); i++) {
		curSum += arr[i];
		if(curSum > maxSum) {
			maxSum = curSum;
			begin = newbegin;
			end = i;
		}
		if(curSum < 0) {
			curSum = 0;
			newbegin = i+1;
		}
	}
	return maxSum;
}

void test_maxSubSum() {
	int len;
	cout<<"输入数组长度:"<<endl;
	cin>>len;
	cout<<"输入数组内容:"<<endl;
	vector<int>  arr;
	int a;
	for(int i = 0; i<len; i++) {
		cin>>a;
		arr.push_back(a);
	}
	int begin,end;
	cout<<maxSubSum(arr,begin,end)<<endl;
	for(int i = begin ; i<=end; i++)
		cout<<arr[i]<<" ";
	cout<<endl;
}

//最长递增子序列 :动态规划的思想
void test_maxIncSeq() {
	const int len=14;
	int arr[len]= {1,9,3,8,11,4,5,6,4,1,9,7,1,7};
	vector<int> vec(&arr[0],&arr[len]);

	vector<int> monoseqlen(len,1);     //以每个元素结尾的最长递增子序列的长度
	vector<int> preindex(len,-1);     //以每个元素结尾的最长递增子序列的上一个节点位置
	int maxmonoseqlen=-1;
	int maxmonoindex=-1;

	for(int i=1; i<len; ++i) {
		int curr=vec[i];
		for(int j=0; j<i; ++j) {
			if(vec[j]<vec[i]) {
				int msl=monoseqlen[j]+1;
				if(msl>monoseqlen[i]) {
					monoseqlen[i]=msl;
					preindex[i]=j;
				}
			}
		}
	}

	for(int i=0; i<len; ++i) { //遍历一次,找到最长递增子序列的长度
		if(monoseqlen[i]>maxmonoseqlen) {
			maxmonoseqlen=monoseqlen[i];
			maxmonoindex=i;
		}
	}

	stack<int> st;   //保存最终子序列结果
	while(maxmonoindex>=0) {
		st.push(vec[maxmonoindex]);
		maxmonoindex=preindex[maxmonoindex];
	}

	vector<int> rect;
	while(!st.empty()) {
		rect.push_back(st.top());
		st.pop();
	}

	vector<int>::iterator itr=rect.begin();
	while(itr!=rect.end()) {
		cout<<*itr++<<"\t";
	}
	cout<<endl;
}

//最长公共子串LCS
const string LCS(const string& str1,const string& str2) {
	int xlen=str1.size();                    //横向长度
	vector<int> tmp(xlen);                   //保存矩阵的上一行
	vector<int> arr(tmp);                    //当前行
	int ylen=str2.size();                    //纵向长度
	int maxele=0;                            //矩阵元素中的最大值
	int pos=0;                               //矩阵元素最大值出现在第几列
	for(int i=0; i<ylen; i++) {
		string s=str2.substr(i,1);
		arr.assign(xlen,0);                  //数组清零
		for(int j=0; j<xlen; j++) {
			if(str1.compare(j,1,s)==0) {            //int compare (size_t pos, size_t len, const string& str)  相同返回0  不同返回-1
				if(j==0)
					arr[j]=1;
				else
					arr[j]=tmp[j-1]+1;               //左上方元素+1
				if(arr[j]>maxele) {
					maxele=arr[j];
					pos=j;
				}
			}
		}

		tmp.assign(arr.begin(),arr.end());
		//   vector的拷贝:https://www.cnblogs.com/xiaopanlyu/p/5644666.html
		//??		tmp = arr;
		//	template <class InputIterator>       string& assign (InputIterator first, InputIterator last);
	}
	string res = str1.substr(pos-maxele+1,maxele);
	return res;
}

void test_LCS() {
	string str1("21232523311324");
	string str2("312123223445");
	string lcs=LCS(str1,str2);
	cout<<lcs<<endl;
}

/*最长公共子序列: 符号约定,C1是S1的最右侧字符,C2是S2的最右侧字符,S1‘是从S1中去除C1的部分,S2'是从S2中去除C2的部分。

LCS(S1,S2)等于下列3项的最大者:

(1)LCS(S1,S2’)

(2)LCS(S1’,S2)

(3)LCS(S1’,S2’)--如果C1不等于C2; LCS(S1',S2')+C1--如果C1等于C2;

边界终止条件:如果S1和S2都是空串,则结果也是空串。*/
int Max(int a,int b,int c,int *max) {           //找最大者时a的优先级别最高,c的最低.最大值保存在*max中
	int res=0;          //res记录来自于哪个单元格
	*max=a;
	if(b>*max) {
		*max=b;
		res=1;
	}
	if(c>*max) {
		*max=c;
		res=2;
	}
	return res;
}
string LCS_2(const string& str1,const string& str2) {
	int xlen=str1.size();               //横向长度
	int ylen=str2.size();               //纵向长度
	if(xlen==0||ylen==0)                //str1和str2中只要有一个为空,则返回空
		return "";
	pair<int,int> arr[ylen+1][xlen+1];    //构造pair二维数组,first记录数据,second记录来源
	for(int i=0; i<=xlen; i++)       //首行清0
		arr[0][i].first=0;
	for(int j=0; j<=ylen; j++)       //首列清0
		arr[j][0].first=0;
	for(int i=1; i<=ylen; i++) {
		char s=str2.at(i-1);
		for(int j=1; j<=xlen; j++) {
			int leftup=arr[i-1][j-1].first;
			int left=arr[i][j-1].first;
			int up=arr[i-1][j].first;
			if(str1.at(j-1)==s)         //C1==C2
				leftup++;
			int max;
			arr[i][j].second=Max(leftup,left,up,&arr[i][j].first);
		}
	}       /*矩阵构造完毕*/
	
	//回溯找出最长公共子序列
	stack<int> st;
	int i=ylen,j=xlen;
	while(i>=0&&j>=0) {
		if(arr[i][j].second==LEFTUP) {
			if(arr[i][j].first==arr[i-1][j-1].first+1)
				st.push(i);
			--i;
			--j;
		} else if(arr[i][j].second==LEFT) {
			--j;
		} else if(arr[i][j].second==UP) {
			--i;
		}
	}
	string res="";
	while(!st.empty()) {
		int index=st.top()-1;
		res.append(str2.substr(index,1));
		st.pop();
	}
	return res;
}
void test_LCS_2() {
	string str1="GCCCTAGCG";
	string str2="GCGCAATG";
	string lcs=LCS(str1,str2);
	cout<<lcs<<endl;
}



int main() {
//	test_maxSubSum();
//	test_maxIncSeq();
//	test_LCS();
	test_LCS_2();
	return 0;
}

参考:https://www.cnblogs.com/zhangchaoyang/articles/2012070.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值