DP总结

这篇博客主要总结了动态规划在解决0-1背包问题、数组分割(值相等或相近)、数组中和最大子数组和最长递增子序列等问题上的关键代码和算法分析。博主提供了时间复杂度和空间复杂度的概述,并链接到相关详细分析。
摘要由CSDN通过智能技术生成

前言

http://oyjh1986.blog.163.com/blog/static/19601607620118293262941/

面试之前,总结一下dp。具体概念,看我的之前写的有关dp的博客,这里主要总结LCS,0-1背包,数组分割,数中和最大的子数组,数组的最长递增子序列,以及字符串的相似度。

接下来分为俩部分,第一部分,引入各个算法的关键代码。第二部分,主要是表格总结,包括时间和空间复杂度,递推关系式。

关键代码分析

LCS:
#include<iostream>
#include<queue>
using namespace std;

//find the longest common string of str1 and str2.
//the Recurrence formula is c[i][j]=max(c[i][j-1],c[i-1][j]),if str1[i]=str2[j];c[i][j]=c[i-1][j-1],if str1[i]!=str2[j].
const int N=10;
int mark[N][N];
void findLCS(char* Str1,char* Str2,int str1Len,int str2Len)
{
	
 int** c=new int*[str1Len+1];

 for(int i=0;i<=str1Len;++i)
    c[i]=new int[str2Len+1];

for(int i=0;i<=str1Len;++i)
c[i][0]=0;

for(int i=0;i<=str2Len;++i)
c[0][i]=0;

  for(int i=1;i<=str1Len;++i) 
  {
   for(int j=1;j<=str2Len;++j)
     {
      if(Str1[i-1]==Str2[j-1])
	  {
		  c[i][j]=c[i-1][j-1]+1;
          mark[i][j]=0;
	  }
	  else
	  {
	    c[i][j]=max(c[i][j-1],c[i-1][j]);
	    if(c[i][j]==c[i][j-1])
			mark[i][j]=-1;
		else
			mark[i][j]=1;

	  }
	  }
  }
  for(int i=0;i<=str1Len;++i)
  delete [] c[i];
  delete c;
}

void getLCS(char* Str1,char* Str2,int str1Len,int str2Len,queue<char>* pqueChar)
{
   if(str1Len==0||str2Len==0)//watch out the boundry 
	   return ;
  if(mark[str1Len][str2Len]==0)
  {
   getLCS(Str1,Str2,str1Len-1,str2Len-1,pqueChar);
   pqueChar->push(Str1[str1Len-1]);
  
  }
  else
	  if(mark[str1Len][str2Len]==1)
		  getLCS(Str1,Str2,str1Len-1,str2Len,pqueChar);
	  else
		  getLCS(Str1,Str2,str1Len,str2Len-1,pqueChar);
		  

}


int main(void)
{
	char* Str1="aefabc";
	char* Str2="egtc";
    queue<char> queChar;
    int str1Len=0;
	int str2Len=0;

	//get the length of two string
	while(*Str1++) str1Len++;
	while(*Str2++) str2Len++;
    Str1=Str1-str1Len-1; 
	Str2=Str2-str2Len-1;

	findLCS(Str1,Str2,str1Len,str2Len);
    getLCS(Str1,Str2,str1Len,str2Len,&queChar);
    
	while(!queChar.empty())
	{
		cout<<queChar.front();
		queChar.pop();
	
	}
    return 0;
}
自己写的代码质量很低,在之前代码的基础上改进了c[i][j],主要把c作为动态数组。时间复杂度O(M*N),空间复杂度 O(2*M*N).主要引入了一个c和mark。

0-1背包问题:

递推关系式 :c[i][j]=c[i-1][j-w[i]]+v[i],if c[i-1][j-w[i]]+v[i]>c[i-1][j]  else c[i][j]=c[i-1][j]。
c[i][j]表示背包最大重量为 j时,前i个物品中取任意个放入背包的最大价值。
#include<iostream>
#include<queue>
using namespace std;

const int N=5;
void printfBack(int** c,int *w,int m,int maxW,queue<int>* pQueInt );
void backProcess(int *w,int *v,int m,int maxW,queue<int>* pQueInt)
{
  int** c=new int*[m+1];

  for(int i=0;i<=m;++i)
	  c[i]=new int[maxW+1];

  //设定初始条件
  for(int i=0;i<=m;++i)
	  c[i][0]=0;

  for(int j=0;j<=maxW;++j)
	  c[0][j]=0;

  for(int j=1;j<=maxW;++j)
  {
     for(int i=1;i<=m;++i)
       if(w[i-1]<=j)
	   {
        if(c[i-1][j]>c[i-1][j-w[i-1]]+ v[i-1])
			c[i][j]=c[i-1][j];
		else
			c[i][j]=c[i-1][j-w[i-1]]+v[i-1];
	   
	   }
	   else
		   c[i][j]=c[i-1][j];
	  
  }
   printfBack(c,w,m,maxW,pQueInt);
   for(int i=0;i<m;++i)
   delete[] c[i];
   delete []c;
}

void printfBack(int** c,int* w,int m,int maxW,queue<int>* pQueInt )
{
	int log[20];
	int j=maxW;

	for(int i=m;i>=1;i--)
    if(c[i][j]==c[i-1][j])
      log[i]=0;
	else
	{ 
	  pQueInt->push(i);
	  log[i]=1;
	  j=j-w[i-1];
	}
	pQueInt->push(c[m][maxW]);
}

int main()
{
	int w[N]={10,3,5,11,8};
	int v[N]={3,5,2,1,6};
    int maxWeight=14;//maxmium weight
	queue<int> queInt;
    backProcess(w,v,N,maxWeight, &queInt);
	while(!queInt.empty())
	{
		cout<<queInt.front()<<endl;
		queInt.pop();

	
	}
	cout<<"最后一个数表示的是背包可以装入的总价值";

return 0;
}
时间复杂度:O(M*maxW),空间复杂度:O(M*maxW)。

数组分割:分割后个数相同,值相等或是最相近。 

递推公式:c[i][j]=c[i][j-data[k-1]];在前k个数里面能否取得i个数,使其和为j,能为true,否为false。时间复杂度,考虑到有一个三重循环,O(N*maxW*N);空间复杂度:O(N*maxW)关键代码如下:

 

   

for(k=1;k<=len;k++)
    for(i=min(k,len/2);i>=1;--i)
        for(j=1;j<=half;j++)
              if(j>=data[k-1]&&dp[i-1][j-data[k-1]])
               dp[i][j]=true;


数组分割:分割后个数可以不同。值相等,或是最相近

依然采用dp去做,递推公式:

for(i=1;i<=len;i++)
  for(j=1;j<=half;++j)
     if(j<data[i-1])
       dp[i][j-1]=dp[i-1][j];
      else
      dp[i][j]=dp[i-1][j]||dp[i-1][j-data[i-1]];


字符串的距离

具体分析见我的博客http://blog.csdn.net/a725sasa/article/details/9404599,时间复杂度:O(N*len),空间复杂度:O(N*len)。

数组中和最大的子数组

时间复杂度:O(N),空间复杂度:O(N*2)

关键代码:

for(i=n-2;i>=0;i--)
   {
     Start[i]=max(A[i],A[i]+Start[i+1]);
     All[i]=max(Start[i],All[i+1]);
   }


最长递增子序列

依然采用dp,编程之美书上给出了时间复杂度Nlg(N),空间复杂度为O(N)的算法,没看懂,腾讯13年的校招就考了这题,所以在这才提一下,一般我会采用LCS的变形去做这题,即,先对数组排序,然后求LCS,思路很明了,当然复杂度没这么好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值