最长(大)递增子序列,最长公共子序列

理解动态规划的基础


一、求最长递增子序列的函数:

  • 方法一:时间复杂度O(N*N)
int LIS(int *dp,int *a,int n){
      //初始比较的最大长度
      int maxlen=0;
      //下面循环第一次就可以直接将长度设置为1
      for (int i = 0; i < n; i++) {
          //每一个数都算一个长度为1的子序列
          int len= 1;
          for (int j = 0; j<i; j++)
              if (a[j]<a[i]) {
              //状态转移方程
              len = max(len,dp[j]+1);//如果后面的数大于前面的某个数,则将该包括该数在内的最长子序列求出
      }
      dp[i]=len;
      //每次都记录最长的那个子序列的长度
      maxlen=max(dp[i],maxlen);
      }
  return  maxlen;
}
  • 方法二:时间复杂度O(N*logN)
int LIS(int *a,int t) {
   int dp[maxn];  //也可以在全局变量声明该数组
   int len;
   dp[1] = a[1];
   len = 1;
   for (int i = 2 ; i <= t ; i++) {
   	if (a[i] > dp[len]) {
   		dp[++len] = a[i];
   		continue;
   	}
   	int l = 1 ,r = len,mid;
      //下面的二分查找是找j使得dp[j]使得dp[j-1]<a[i]<dp[j]并将dp[j]替换为a[i],尽管形式上是错误的,但是其最长序列的长度已经被记录,对结果无影响
   	while(l < r) {
   		mid = (l + r) / 2;
   		if(dp[mid] < a[i])
   			l = mid + 1 ;
   		else
   			r = mid;
   	}
   	dp[l] = a[i];
   }
   return len;
}

二、求最大递增子序列的函数:(借用了最长递增子序列的思想)

int BIS(int *dp,int *a,int n){
      //初始比较的最大和
      int maxsum=0;
      int sum;
      for (int i = 0; i < n; i++) {
          //每一个数都算一个子序列的和
          sum=a[i];
          for (int j = 0; j<i; j++)
              if (a[j]<a[i]) {
              //状态转移方程
              sum= max(sum,dp[j]+a[i]);
          }
          dp[i]=sum;
          //每次都记录最大的那个子序列的长度
          if(dp[i]>maxsum)
          maxsum=dp[i];
      }
      return  maxsum;
}

三、求最长公共子序列函数:(第一个仅求长度,第二个求具体内容)

  • 求LCS长度
void lcs(int i, int j){
   for(i=1; i<=len1; i++){
      for(j=1; j<=len2; j++){       
          if(a[i-1] == b[j-1])                 
              dp[i][j] = dp[i-1][j-1] + 1;
          else 
              dp[i][j] = max(dp[i-1][j],dp[i][j-1])
       }
    }
}
  • 求LCS具体内容(在求长度的函数基础上)
void llcs(){
   int i, j, z = 0;
   char c[1001];		//也能是int类型的数组
   memset(c, 0, sizeof(c));
   i = len1, j = len2;
   //刚好是LCS()函数的逆过程只是保存每次相等的值
   while(i!=0 && j!=0)
   {
       if(a[i-1] == b[j-1])
       {
           c[z++] = a[--i];
           j--;
       }
       else if(dp[i-1][j] < dp[i][j-1])
           j--;
       else if(dp[i-1][j] >= dp[i][j-1])
           i--;
   }
   for(i=z-1; i>=0; i--)
       printf("%c", c[i]);
   printf("\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值